Валидация, prepared statements
Никогда не доверяй входным данным. Любые данные от пользователя (формы, URL-параметры, заголовки, JSON) могут содержать вредоносный контент. Валидация и параметризованные запросы — первая линия защиты.
Prepared statements (параметризованные запросы) — защита от SQL-инъекций:
// ОПАСНО — конкатенация строк:
String query = "SELECT * FROM users WHERE email = '" + email + "'";
// БЕЗОПАСНО — prepared statement:
PreparedStatement ps = conn.prepareStatement(
"SELECT * FROM users WHERE email = ?"
);
ps.setString(1, email); // email вставляется как данные, не как SQL
JPA/Hibernate по умолчанию используют prepared statements — ещё одна причина предпочитать их нативному SQL.
Валидация входных данных в Spring Boot:
public record CreateUserDto(
@NotBlank String username,
@Email String email,
@Size(min = 8, max = 64) String password,
@Pattern(regexp = "^[a-zA-Z0-9_]+$") String nickname
) {}
@PostMapping("/users")
public ResponseEntity<UserDto> create(@Valid @RequestBody CreateUserDto dto) {
// если dto не прошёл — автоматически 400 Bad Request
}
Копнуть глубже
Два уровня валидации. Валидация на клиенте (JavaScript в браузере) — для UX, не для безопасности. Её легко обойти (curl, Postman, browser devtools). Валидация на сервере — обязательна, это единственная надёжная защита. Проверяйте всё что пришло от клиента, даже если ваш UI «не позволяет» ввести неправильные данные.
Whitelist vs Blacklist. Blacklist-подход: «запрещу ввод <script> тегов» — легко обойти альтернативным кодированием (<scr\x69pt>, Unicode). Whitelist-подход: «разрешу только то, что точно безопасно» — позитивные шаблоны @Pattern(regexp = "^[a-zA-Z0-9]+$"). Whitelist надёжнее.
Output encoding — дополнительная защита. Даже если вредоносные данные попали в БД, их нужно безопасно вывести:
- В HTML: эскейпинг
<→<(Thymeleaf делает автоматически черезth:text) - В JSON: стандартная сериализация Jackson безопасна
- В SQL: prepared statements
Bean Validation стандартные аннотации (javax.validation / jakarta.validation):
@NotNull,@NotEmpty,@NotBlank— разница: NotNull не проверяет пустую строку, NotEmpty проверяет длину ≥ 1, NotBlank — непустую строку без пробелов@Min,@Max,@Positive,@PositiveOrZero— числовые границы@Past,@Future— для дат@Validна вложенных объектах — каскадная валидация
• разницу whitelist и blacklist подходов к валидации (если дошёл до 2-го слоя).