Безопасность Java приложений: топ-10 уязвимостей на практике
Безопасность Java-приложений — это не просто галочка в чек-листе, а критически важный аспект разработки. По данным OWASP, более 70% современных веб-приложений содержат хотя бы одну критическую уязвимость. В этой статье мы разберем 10 самых распространенных угроз с реальными примерами кода и способами их устранения. Материал будет полезен как начинающим, так и опытным Java-разработчикам.
1. SQL-инъекции (Injection)
SQL-инъекция остается лидером среди уязвимостей. Атакующий может внедрить вредоносный SQL-код через пользовательский ввод.
Уязвимый код:
String query = "SELECT * FROM users WHERE username = '" + username + "'";
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(query);
Исправленный код (использование PreparedStatement):
String query = "SELECT * FROM users WHERE username = ?";
PreparedStatement pstmt = connection.prepareStatement(query);
pstmt.setString(1, username);
ResultSet rs = pstmt.executeQuery();
2. XSS (Cross-Site Scripting)
XSS-атаки позволяют внедрять клиентские скрипты в веб-страницы. Основная защита — экранирование вывода.
Уязвимый код (JSP):
<%= request.getParameter("comment") %>
Исправленный код:
<%= Encode.forHtml(request.getParameter("comment")) %>
Используйте библиотеку OWASP Java Encoder для надежного экранирования:
import org.owasp.encoder.Encode;
String safeOutput = Encode.forHtml(userInput);
3. Небезопасная десериализация
Java-десериализация может привести к удаленному выполнению кода (RCE).
Уязвимый код:
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
Object obj = ois.readObject(); // Опасность!
Рекомендации по защите:
- Не десериализуйте данные из ненадежных источников
- Используйте белый список классов при десериализации
- Применяйте JSON или XML вместо сериализации Java
// Безопасный подход с проверкой класса
ObjectInputStream ois = new ObjectInputStream(inputStream) {
@Override
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
if (!allowedClasses.contains(desc.getName())) {
throw new InvalidClassException(desc.getName(), "Unauthorized deserialization");
}
return super.resolveClass(desc);
}
};
4. CSRF (Cross-Site Request Forgery)
CSRF-атаки заставляют пользователя выполнять нежелательные действия на сайте, где он аутентифицирован.
Защита с помощью токенов (Spring Security):
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
}
}
Добавление токена в форму:
<form action="/transfer" method="POST">
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
<input type="text" name="amount"/>
<button type="submit">Перевести</button>
</form>
5. Утечка информации через исключения
Детальные сообщения об ошибках могут раскрыть внутреннюю структуру приложения.
Уязвимый код:
try {
// бизнес-логика
} catch (SQLException e) {
response.getWriter().println("Ошибка: " + e.getMessage()); // Утечка!
}
Исправленный код:
try {
// бизнес-логика
} catch (Exception e) {
logger.error("Ошибка при обработке запроса", e);
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Внутренняя ошибка сервера");
}
6. Небезопасная аутентификация
Слабые пароли и отсутствие блокировки после неудачных попыток — частая проблема.
Правильная реализация хеширования паролей:
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
String hashedPassword = encoder.encode(plainPassword);
// Проверка пароля
boolean matches = encoder.matches(plainPassword, hashedPassword);
7. Недостаточная проверка доступа
Отсутствие проверки прав на уровне методов может привести к эскалации привилегий.
Использование аннотаций Spring Security:
@PreAuthorize("hasRole('ADMIN')")
@PostMapping("/admin/deleteUser")
public ResponseEntity<String> deleteUser(@RequestParam Long userId) {
// только для администраторов
userService.deleteUser(userId);
return ResponseEntity.ok("Пользователь удален");
}
8. Небезопасная конфигурация CORS
Широкие настройки CORS могут привести к утечке данных.
Опасная конфигурация:
@CrossOrigin(origins = "*") // Разрешает все домены!
Безопасная конфигурация:
@CrossOrigin(origins = "https://trusted-site.com", allowedHeaders = "Authorization")
9. Уязвимости в зависимостях
Использование старых версий библиотек с известными уязвимостями.
Рекомендации:
- Регулярно обновляйте зависимости через Maven/Gradle
- Используйте OWASP Dependency-Check для автоматического сканирования
- Настройте Dependabot в GitHub для автоматических обновлений
// Пример плагина Maven для проверки зависимостей
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId