Bug2Lab · Secure Code · Java / JDBC

SQL Injection через конкатенацию строки запроса

Приложение строит SQL через строковую конкатенацию с параметром пользователя. Атакующий подсовывает фрагмент SQL и получает данные, которые не должен видеть. Фикс — всегда использовать подготовленные выражения (PreparedStatement).

1
Как выглядит атака
Эндпоинт /user?id=1 OR 1=1 возвращает вообще всех пользователей, хотя ожидался один.
GET /user?id=1%20OR%201=1
200 OK (application/json)
[
 {"id":1,"email":"ceo@company.example"},
 {"id":2,"email":"client@example.com"},
 ...
]
2
Почему это стало возможным
Код собирает SQL как строку. Значение из запроса вставляется прямо внутрь без параметров.
Проблемный код
31String sql = "SELECT * FROM users WHERE id = " + req.getParameter("id");
32Statement st = conn.createStatement();
33ResultSet rs = st.executeQuery(sql); // ❌ уязвимо
3
Как это чинится правильно
Используем PreparedStatement, где параметры подставляются безопасно и не «ломают» структуру SQL.
Исправленный паттерн
31String sql = "SELECT * FROM users WHERE id = ?";
32PreparedStatement ps = conn.prepareStatement(sql);
33ps.setString(1, req.getParameter("id")); // ✅ безопасная подстановка
34ResultSet rs = ps.executeQuery();

bug2regressРегрессионный тест (стоп-кран)

Тест отправляет id=1 OR 1=1. Если сервис возвращает больше одного пользователя — билд стопается.

#!/bin/bash
# sqlinj-check.sh
RESP=$(curl -s "https://staging.example.internal/user?id=1%20OR%201=1")

COUNT=$(echo "$RESP" | grep -o '"id":' | wc -l)

if [ "$COUNT" -gt 1 ]; then
  echo "[BLOCK] SQLi: эндпоинт вернул больше одного пользователя"
  exit 1
fi

echo "[OK] Параметризованный запрос защищает от SQLi"
exit 0

Это фиксирует стандарт: никаких строковых конкатенаций для SQL вообще.

Проверка пониманияГде баг?

Стандарт:ни один SQL-запрос не строится через конкатенацию строк с пользовательским вводом. Никогда.

Теория (по желанию) SQL-инъекция = мгновенный слив базы