Ответ
Самый простой и обязательный способ — заменить конкатенацию на PreparedStatement. Это мгновенно устраняет уязвимость к SQL-инъекциям и часто улучшает производительность.
До (опасный код):
String userId = request.getParameter("id");
// Уязвимость: если userId = "1; DROP TABLE users --", запрос выполнит удаление таблицы.
String sql = "SELECT * FROM users WHERE id = " + userId;
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(sql);
После (безопасный код с PreparedStatement):
String userId = request.getParameter("id");
String sql = "SELECT * FROM users WHERE id = ?"; // Плейсхолдер '?'
PreparedStatement pstmt = connection.prepareStatement(sql);
// Параметр безопасно подставляется, инъекция невозможна.
pstmt.setString(1, userId); // Явное указание типа данных
ResultSet rs = pstmt.executeQuery();
Преимущества PreparedStatement:
- Безопасность: Параметры обрабатываются как данные, а не как часть SQL-команды.
- Производительность: Скомпилированный запрос может кешироваться СУБД при повторном использовании.
- Читаемость: Запрос легче читать и поддерживать.
Дополнительные шаги для сложных запросов:
- Использовать ORM-фреймворк (JPA/Hibernate), который по умолчанию использует параметризованные запросы.
- Проверить и оптимизировать индексы для условий в
WHERE. - Воспользоваться встроенным валидатором SQL в IDE для исправления синтаксических ошибок.