Риск (кратко) - SQL‑инъекция: при конкатенации пользовательских данных в SQL строка запроса может быть изменена атакующим, что ведёт к утечке/изменению/удалению данных или обходу аутентификации (примеры типа 1=1 \;1=1\;1=1). - Факторы риска: прямое склеивание строк запроса, недостаточная валидация, избыточные привилегии БД, динамическое подставление имен таблиц/столбцов без белого списка. Основная защита - Использовать подготовленные выражения (prepared statements / parameterized queries) с привязкой параметров. - Валидировать / белить вход для частей SQL, которые нельзя параметризовать (identifiers, ORDER BY). - Минимизировать привилегии учётных записей БД. - Логировать и мониторить аномалии. Реализации (коротко, уязвимый → безопасный) 1) PHP PDO Уязвимо: ``` $id = $_GET['id']; $sql = "SELECT * FROM users WHERE id = $id"; $db->query($sql); ``` Безопасно: ``` $stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id"); $stmt->execute([':id' => $id]); $row = $stmt->fetch(); ``` 2) Python (psycopg2, PostgreSQL) Уязвимо: ``` cur.execute("SELECT * FROM users WHERE login = '%s'" % login) ``` Безопасно: ``` cur.execute("SELECT * FROM users WHERE login = %s", (login,)) row = cur.fetchone() ``` 3) Python (sqlite3) Безопасно: ``` cur.execute("SELECT * FROM items WHERE price <= ?", (max_price,)) ``` 4) Node.js (mysql2 / mysql) Уязвимо: ``` conn.query("SELECT * FROM users WHERE name = '" + name + "'"); ``` Безопасно: ``` conn.execute("SELECT * FROM users WHERE name = ?", [name]) ``` 5) Java (JDBC) Безопасно: ``` PreparedStatement ps = conn.prepareStatement("SELECT * FROM users WHERE email = ?"); ps.setString(1, email); ResultSet rs = ps.executeQuery(); ``` 6) C# (SqlClient) Безопасно: ``` using (var cmd = new SqlCommand("SELECT * FROM Users WHERE Id = @id", conn)) { cmd.Parameters.AddWithValue("@id", id); var rdr = cmd.ExecuteReader(); } ``` Замечания и лучшие практики - Prepared statements не параметризуют имена таблиц/столбцов и SQL‑фрагменты. Для них используйте белые списки и валидацию. - Для числовых лимитов/offset лучше явно приводить к целому: пример default лимита 10\;1010 — `limit = int(request.args.get('limit', 10))`. - Не доверяйте проверкам на клиенте; валидируйте на сервере. - Привилегии БД должны быть минимальными: приложение — только SELECT/INSERT/UPDATE/DELETE по необходимости. Если нужно, могу прислать пример для конкретного языка/БД или показать защиту для динамических идентификаторов (таблицы/ORDER BY).
- SQL‑инъекция: при конкатенации пользовательских данных в SQL строка запроса может быть изменена атакующим, что ведёт к утечке/изменению/удалению данных или обходу аутентификации (примеры типа 1=1 \;1=1\;1=1).
- Факторы риска: прямое склеивание строк запроса, недостаточная валидация, избыточные привилегии БД, динамическое подставление имен таблиц/столбцов без белого списка.
Основная защита
- Использовать подготовленные выражения (prepared statements / parameterized queries) с привязкой параметров.
- Валидировать / белить вход для частей SQL, которые нельзя параметризовать (identifiers, ORDER BY).
- Минимизировать привилегии учётных записей БД.
- Логировать и мониторить аномалии.
Реализации (коротко, уязвимый → безопасный)
1) PHP PDO
Уязвимо:
```
$id = $_GET['id'];
$sql = "SELECT * FROM users WHERE id = $id";
$db->query($sql);
```
Безопасно:
```
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id");
$stmt->execute([':id' => $id]);
$row = $stmt->fetch();
```
2) Python (psycopg2, PostgreSQL)
Уязвимо:
```
cur.execute("SELECT * FROM users WHERE login = '%s'" % login)
```
Безопасно:
```
cur.execute("SELECT * FROM users WHERE login = %s", (login,))
row = cur.fetchone()
```
3) Python (sqlite3)
Безопасно:
```
cur.execute("SELECT * FROM items WHERE price <= ?", (max_price,))
```
4) Node.js (mysql2 / mysql)
Уязвимо:
```
conn.query("SELECT * FROM users WHERE name = '" + name + "'");
```
Безопасно:
```
conn.execute("SELECT * FROM users WHERE name = ?", [name])
```
5) Java (JDBC)
Безопасно:
```
PreparedStatement ps = conn.prepareStatement("SELECT * FROM users WHERE email = ?");
ps.setString(1, email);
ResultSet rs = ps.executeQuery();
```
6) C# (SqlClient)
Безопасно:
```
using (var cmd = new SqlCommand("SELECT * FROM Users WHERE Id = @id", conn)) {
cmd.Parameters.AddWithValue("@id", id);
var rdr = cmd.ExecuteReader();
}
```
Замечания и лучшие практики
- Prepared statements не параметризуют имена таблиц/столбцов и SQL‑фрагменты. Для них используйте белые списки и валидацию.
- Для числовых лимитов/offset лучше явно приводить к целому: пример default лимита 10\;1010 — `limit = int(request.args.get('limit', 10))`.
- Не доверяйте проверкам на клиенте; валидируйте на сервере.
- Привилегии БД должны быть минимальными: приложение — только SELECT/INSERT/UPDATE/DELETE по необходимости.
Если нужно, могу прислать пример для конкретного языка/БД или показать защиту для динамических идентификаторов (таблицы/ORDER BY).