Разберите фрагмент SQL: SELECT * FROM users WHERE id = " + userId + "; — объясните уязвимость и покажите безопасную альтернативу с параметризованными запросами
Проблема: строковая конкатенация пользовательских данных в SQL приводит к SQL‑инъекции — злоумышленник подставит специально сформированный userId и изменит структуру запроса. Пример уязвимого фрагмента: SELECT * FROM users WHERE id = " + userId + "; Как работает атака (пример полезной нагрузки): userId = "' OR 1=11=11=1 --" В результате получится запрос: SELECT * FROM users WHERE id = '' OR 1=11=11=1 --"; Это вернёт все строки (или позволит выполнить произвольный SQL, например DROP) — опасно. Безопасная альтернатива: параметризованные запросы (prepared statements / параметризация), где СУБД отдельно получает текст запроса и значения параметров, поэтому ввод не меняет синтаксис запроса. Примеры. Java (JDBC): PreparedStatement ps = conn.prepareStatement("SELECT * FROM users WHERE id = ?"); ps.setInt(1, userId); // или ps.setString(1, userId); ResultSet rs = ps.executeQuery(); Python (psycopg2, PostgreSQL): cur.execute("SELECT * FROM users WHERE id = %s", (user_id,)) rows = cur.fetchall() Node.js (pg): client.query('SELECT * FROM users WHERE id = $1', [userId]) .then(res => { /* ... */ }); PHP (PDO): $stmt = $pdo->prepare('SELECT * FROM users WHERE id = :id'); $stmt->execute(['id' => $userId]); $rows = $stmt->fetchAll(); Дополнительно: - Для числового id применяйте валидацию/выполните приведение к числу (whitelist): например, убедитесь, что id — целое. - Применяйте принцип наименьших привилегий для учётных записей БД. - Логируйте и ограничивайте ошибки, чтобы не выдавать внутренние сообщения.
Пример уязвимого фрагмента:
SELECT * FROM users WHERE id = " + userId + ";
Как работает атака (пример полезной нагрузки):
userId = "' OR 1=11=11=1 --"
В результате получится запрос:
SELECT * FROM users WHERE id = '' OR 1=11=11=1 --";
Это вернёт все строки (или позволит выполнить произвольный SQL, например DROP) — опасно.
Безопасная альтернатива: параметризованные запросы (prepared statements / параметризация), где СУБД отдельно получает текст запроса и значения параметров, поэтому ввод не меняет синтаксис запроса.
Примеры.
Java (JDBC):
PreparedStatement ps = conn.prepareStatement("SELECT * FROM users WHERE id = ?");
ps.setInt(1, userId); // или ps.setString(1, userId);
ResultSet rs = ps.executeQuery();
Python (psycopg2, PostgreSQL):
cur.execute("SELECT * FROM users WHERE id = %s", (user_id,))
rows = cur.fetchall()
Node.js (pg):
client.query('SELECT * FROM users WHERE id = $1', [userId])
.then(res => { /* ... */ });
PHP (PDO):
$stmt = $pdo->prepare('SELECT * FROM users WHERE id = :id');
$stmt->execute(['id' => $userId]);
$rows = $stmt->fetchAll();
Дополнительно:
- Для числового id применяйте валидацию/выполните приведение к числу (whitelist): например, убедитесь, что id — целое.
- Применяйте принцип наименьших привилегий для учётных записей БД.
- Логируйте и ограничивайте ошибки, чтобы не выдавать внутренние сообщения.