Введение: почему безопасность Java-приложений критична?
Java остается одним из самых популярных языков для создания корпоративных и веб-приложений. Однако популярность влечет за собой и повышенное внимание злоумышленников. По данным OWASP (Open Web Application Security Project), большинство взломов происходят из-за типовых ошибок разработчиков, а не из-за уязвимостей самой платформы. В этой статье мы разберем топ-10 самых опасных уязвимостей Java-приложений, покажем примеры кода и дадим практические рекомендации по защите.
1. SQL-инъекции (SQL Injection)
Проблема: Передача непроверенных пользовательских данных в SQL-запрос.
Пример уязвимого кода:
String query = "SELECT * FROM users WHERE username = '" + userInput + "'";
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, userInput);
ResultSet rs = pstmt.executeQuery();
2. Межсайтовый скриптинг (XSS)
Проблема: Внедрение вредоносных скриптов в веб-страницу через пользовательский ввод.
Пример уязвимости:
String comment = request.getParameter("comment");
out.println("<div>" + comment + "</div>");
Решение: Экранируйте HTML-символы. Используйте библиотеки вроде OWASP Java Encoder.
import org.owasp.encoder.Encode;
String comment = request.getParameter("comment");
out.println("<div>" + Encode.forHtml(comment) + "</div>");
3. Небезопасная десериализация
Проблема: Злоумышленник может передать сериализованный объект, который при десериализации выполнит произвольный код.
Пример:
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
Object obj = ois.readObject(); // Опасно!
Решение:
- Не десериализуйте данные из ненадежных источников.
- Используйте белые списки классов (look-ahead deserialization).
- Применяйте JSON (Jackson) с настройками безопасности.
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); // Небезопасно!
// Правильно: отключить defaultTyping и использовать @JsonTypeInfo
4. Подделка межсайтовых запросов (CSRF)
Проблема: Злоумышленник заставляет пользователя выполнить нежелательное действие на доверенном сайте.
Решение: Используйте CSRF-токены. В Spring Security это встроено:
<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. Недостатки аутентификации и управления сессиями
Проблемы: Слабые пароли, незащищенные cookies, фиксированные сессии.
Рекомендации:
- Используйте bcrypt или Argon2 для хеширования паролей.
- Устанавливайте флаги
HttpOnlyиSecureдля cookies. - Реализуйте блокировку после N неудачных попыток входа.
PasswordEncoder encoder = new BCryptPasswordEncoder();
String hashedPassword = encoder.encode(plainPassword);
6. Небезопасная конфигурация (Security Misconfiguration)
Проблема: Включенные debug-режимы, стандартные пароли, незащищенные endpoints.
Решение:
- Отключите отображение стека ошибок в production.
- Используйте Spring Security для настройки прав доступа.
- Регулярно обновляйте библиотеки.
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and().formLogin();
}
}
7. Раскрытие конфиденциальных данных
Проблема: Хранение паролей в открытом виде, передача данных без шифрования.
Рекомендации:
- Используйте HTTPS (TLS 1.2+).
- Не храните секреты в коде — используйте переменные окружения или Vault.
- Шифруйте чувствительные данные в БД (AES-256).
// Пример шифрования с помощью Java Cryptography Extension (JCE)
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encryptedData = cipher.doFinal(plainText.getBytes());
8. Внедрение XML (XXE)
Проблема: Обработка XML с внешними сущностями может привести к чтению файлов или DoS-атаке.
Пример уязвимого парсера:
DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = db.parse(inputStream); // Опасно!
Решение: Отключите внешние сущности:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
9. Использование компонентов с известными уязвимостями
Проблема: Ста