Java: никогда не доверяйте внешнему вводу напрямую
Пользовательский ввод нельзя сразу подставлять в SQL, путь к файлу или бизнес-логику.
Плохой вариант:
String sql = "SELECT * FROM users WHERE email = '" + email + "'";
Files.readString(Path.of("/data/" + filename));
int age = Integer.parseInt(request.getParameter("age"));
На вид обычный код, но в нём сразу несколько проблем:
• SQL-инъекции;
• path traversal через ../;
• некорректные типы и диапазоны;
• мусорные данные, которые ломают логику дальше по системе.
Правильный подход - валидировать данные на границе приложения и использовать безопасные API.
if (!EMAIL.matcher(email).matches()) {
throw new BadRequestException("invalid email");
}
PreparedStatement ps = conn.prepareStatement(
"SELECT * FROM users WHERE email = ?"
);
ps.setString(1, email);
Для файлов - нормализовать путь и проверять, что пользователь не вышел за разрешённую директорию:
Path base = Path.of("/data").toAbsolutePath().normalize();
Path file = base.resolve(filename).normalize();
if (!file.startsWith(base)) {
throw new SecurityException("path escape blocked");
}
А для DTO лучше сразу описывать правила:
public record SignupRequest(
@NotBlank @Email String email,
@Min(18) @Max(120) int age
) {}
Чем раньше вы отсекаете плохие данные, тем меньше шансов, что они превратятся в уязвимость внутри системы.
Пользовательский ввод нельзя сразу подставлять в SQL, путь к файлу или бизнес-логику.
Плохой вариант:
String sql = "SELECT * FROM users WHERE email = '" + email + "'";
Files.readString(Path.of("/data/" + filename));
int age = Integer.parseInt(request.getParameter("age"));
На вид обычный код, но в нём сразу несколько проблем:
• SQL-инъекции;
• path traversal через ../;
• некорректные типы и диапазоны;
• мусорные данные, которые ломают логику дальше по системе.
Правильный подход - валидировать данные на границе приложения и использовать безопасные API.
if (!EMAIL.matcher(email).matches()) {
throw new BadRequestException("invalid email");
}
PreparedStatement ps = conn.prepareStatement(
"SELECT * FROM users WHERE email = ?"
);
ps.setString(1, email);
Для файлов - нормализовать путь и проверять, что пользователь не вышел за разрешённую директорию:
Path base = Path.of("/data").toAbsolutePath().normalize();
Path file = base.resolve(filename).normalize();
if (!file.startsWith(base)) {
throw new SecurityException("path escape blocked");
}
А для DTO лучше сразу описывать правила:
public record SignupRequest(
@NotBlank @Email String email,
@Min(18) @Max(120) int age
) {}
Чем раньше вы отсекаете плохие данные, тем меньше шансов, что они превратятся в уязвимость внутри системы.