← Назад к вопросам
Что такое SQL Injection?
1.8 Middle🔥 121 комментариев
#Безопасность#Базы данных и SQL
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
SQL Injection — критическая уязвимость безопасности
SQL Injection — это одна из самых опасных и распространённых уязвимостей. Входит в OWASP Top 10.
Что такое SQL Injection?
SQL Injection происходит, когда пользовательский ввод внедряется в SQL запрос без должной санитизации.
Классический пример уязвимости
// УЯЗВИМЫЙ КОД
const username = req.body.username; // "admin' --"
const password = req.body.password;
const query = `
SELECT * FROM users
WHERE username = '${username}'
AND password = '${password}'
`;
// Результирующий SQL:
// SELECT * FROM users WHERE username = 'admin' --'
// Комментарий убирает проверку пароля!
Типы SQL Injection атак
1. Authentication Bypass
// Ввод: ' OR '1'='1
// Условие '1'='1' всегда true
2. Data Exfiltration (утечка данных)
// Ввод: ' UNION SELECT password FROM admin --
// Возвращает пароли администраторов
3. Data Destruction (удаление данных)
// Ввод: '; DROP TABLE users; --
// Удаляет таблицу!
Правильное решение: Prepared Statements
С использованием параметризованных запросов:
const pg = require('pg');
const pool = new pg.Pool();
async function authenticateUser(username, password) {
const query = `
SELECT * FROM users
WHERE username = $1
AND password = $2
`;
// Параметры передаются отдельно от SQL
const result = await pool.query(query, [username, password]);
return result.rows[0];
}
// Даже если пользователь введёт: ' OR '1'='1
// Это будет воспринято как строковой литерал
SQL Injection в Express приложении
Уязвивое:
app.get('/user/:id', async (req, res) => {
const id = req.params.id;
const query = `SELECT * FROM users WHERE id = ${id}`;
// Атака: GET /user/1 OR 1=1
// Вернёт всех пользователей!
const result = await pool.query(query);
res.json(result.rows);
});
Безопасное:
app.get('/user/:id', async (req, res) => {
const id = req.params.id;
const query = `SELECT * FROM users WHERE id = $1`;
// Параметризованный запрос
const result = await pool.query(query, [id]);
res.json(result.rows);
});
Защита от SQL Injection
Checklist:
// 1. ВСЕГДА используй параметризованные запросы
await pool.query(`SELECT * FROM users WHERE id = $1`, [userId]);
// 2. НЕ конкатенируй пользовательский ввод
// await pool.query(`SELECT * FROM users WHERE id = ${userId}`); // НЕПРАВИЛЬНО
// 3. Валидируй ввод
const userId = parseInt(req.params.id);
if (isNaN(userId)) return res.status(400).json({ error: 'Invalid ID' });
// 4. Используй ORM когда возможно
const user = await User.findByPk(userId); // Безопасно
// 5. Минимизируй права БД пользователя
// Production: только SELECT, INSERT, UPDATE
// НЕ DROP, ALTER, CREATE
// 6. Логируй подозрительную активность
Примеры по разным БД
PostgreSQL:
await pool.query(
'SELECT * FROM users WHERE email = $1 AND status = $2',
[email, status]
);
MySQL:
connection.query(
'SELECT * FROM users WHERE id = ?',
[userId],
(error, results) => {...}
);
Real-world пример: Правильная аутентификация
const bcrypt = require('bcrypt');
async function login(username, password) {
// 1. Параметризованный запрос
const result = await pool.query(
'SELECT * FROM users WHERE username = $1',
[username]
);
const user = result.rows[0];
if (!user) {
return { success: false, error: 'User not found' };
}
// 2. Сравниваем пароли (хешированные)
const passwordMatch = await bcrypt.compare(password, user.password_hash);
if (!passwordMatch) {
return { success: false, error: 'Invalid password' };
}
return { success: true, user };
}
Key takeaway
- SQL Injection = критическая уязвимость
- Решение: Prepared Statements
- Никогда не конкатенируй пользовательский ввод в SQL
- Используй ORM когда возможно
- Валидируй входные данные
- Минимизируй права БД пользователя