Введение: Почему безопасность Java-приложений — это не опция, а необходимость
Java остается одним из самых популярных языков для разработки корпоративных и веб-приложений. Однако популярность влечет за собой и повышенное внимание со стороны злоумышленников. По данным OWASP (Open Web Application Security Project), уязвимости в коде ежегодно приводят к утечкам данных и финансовым потерям на миллиарды долларов. В этой статье мы разберем топ-10 уязвимостей Java-приложений, покажем реальные примеры кода и дадим конкретные рекомендации по защите. Материал будет полезен как начинающим, так и опытным разработчикам, стремящимся писать безопасный код.
1. Инъекции: SQL, LDAP и Command Injection
Инъекции остаются королем уязвимостей. Самый частый случай — SQL-инъекция, когда пользовательский ввод напрямую конкатенируется в SQL-запрос.
Пример уязвимого кода
String query = "SELECT * FROM users WHERE username = '" + request.getParameter("user") + "'";
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(query);
Если злоумышленник передаст admin' OR '1'='1, он получит доступ ко всем пользователям.
Как защититься
- Используйте PreparedStatement: параметризованные запросы автоматически экранируют ввод.
- Валидируйте входные данные на стороне сервера (белые списки).
- Для LDAP и команд ОС применяйте экранирование и избегайте вызова
Runtime.exec()с пользовательскими данными.
// Безопасный вариант
String query = "SELECT * FROM users WHERE username = ?";
PreparedStatement pstmt = connection.prepareStatement(query);
pstmt.setString(1, request.getParameter("user"));
ResultSet rs = pstmt.executeQuery();
2. Нарушение аутентификации и управления сессиями
Слабая аутентификация — вторая по опасности уязвимость. Часто встречаются: отсутствие ограничения на количество попыток входа, хранение паролей в открытом виде, предсказуемые session ID.
Рекомендации
- Храните пароли только в виде хешей с солью (например, bcrypt или Argon2).
- Используйте
SecureRandomдля генерации сессионных токенов. - Установите таймауты сессий и механизм «запомнить меня» с безопасным токеном.
// Генерация безопасного session ID
import java.security.SecureRandom;
String sessionId = new SecureRandom().ints(48, 122)
.filter(i -> Character.isLetterOrDigit(i))
.limit(64)
.collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
.toString();
3. XSS (Межсайтовый скриптинг)
XSS позволяет внедрить вредоносный JavaScript в страницу, которую просматривают другие пользователи. Это особенно опасно для веб-приложений на Java с JSP или Thymeleaf.
Пример уязвимости
<div>${userComment}</div>
Если userComment содержит <script>alert('XSS')</script>, код выполнится в браузере.
Защита
- Экранируйте вывод: в JSP используйте
c:outилиfn:escapeXml(). - Для Thymeleaf —
th:utextопасен, используйтеth:text. - Применяйте Content Security Policy (CSP) заголовки.
4. Небезопасная десериализация
Java-десериализация — одна из самых критичных уязвимостей, позволяющая выполнить произвольный код (RCE). Злоумышленник может подменить поток байтов и внедрить вредоносный объект.
Пример атаки
ObjectInputStream ois = new ObjectInputStream(request.getInputStream());
Object obj = ois.readObject(); // Опасность!
Как защититься
- Не десериализуйте данные из ненадежных источников.
- Используйте белые списки классов (например, через
ValidatingObjectInputStreamиз библиотеки Apache Commons IO). - Рассмотрите замену на JSON/XML (Jackson, Gson) с ограничением типов.
// Использование ValidatingObjectInputStream
ValidatingObjectInputStream vois = new ValidatingObjectInputStream(inputStream);
vois.accept(User.class, Order.class);
Object obj = vois.readObject();
5. Подделка межсайтовых запросов (CSRF)
CSRF-атака заставляет авторизованного пользователя выполнить нежелательное действие (например, перевод денег) без его ведома.
Защита
- Используйте CSRF-токены в формах и AJAX-запросах.
- Spring Security предоставляет встроенную защиту — включите
csrf().enable(). - Проверяйте заголовки
OriginиReferer.
6. Небезопасная конфигурация
Уязвимости часто возникают из-за стандартных настроек: открытые порты, слабые пароли, включенные режимы отладки, устаревшие библиотеки.
Рекомендации
- Регулярно обновляйте зависимости (используйте OWASP Dependency-Check).
- Отключайте JSP source debugging в production.
- Не храните пароли и API-ключи в коде — используйте переменные окружения или Vault.
7. Недостатки контроля доступа
Нарушение прав доступа (IDOR — Insecure Direct Object References) позволяет пользователю получить данные другого пользователя, просто изменив ID в URL.
Пример
GET /api/user/12345
Если нет проверки, пользователь может получить данные любого профиля.