flawopen.com/SQL Injection/Числовые ID
Чем опасно форматирование строки даже для числовых ID?
Риск не зависит от реального смысла значения: запрос собирается склейкой текста. «Это всегда число» — предположение о данных, а не гарантия, обеспеченная кодом.
Когда предположение нарушается
Параметр URL или поле формы передаётся как текст независимо от ожидаемого типа столбца базы данных. Без явной проверки фреймворк не мешает отправить id=1 OR 1=1 вместо числа до того, как значение попадёт в код.
Код, безопасный сегодня благодаря ID из доверенного внутреннего источника, станет уязвимым, если новый вызывающий код передаст в ту же функцию пользовательское значение. Уязвимость всё это время оставалась скрытой.
Особенно в языках с динамической типизацией значение, которое выглядит числом в журнале, может быть строкой с дополнительными символами. Без явной проверки ожидаемый тип не гарантирует фактический.
Параметризуйте запрос даже после проверки типа
Проверьте ID на соответствие ожидаемому формату приложения, затем передайте его через API параметров драйвера базы данных. Проверка защищает контракт входных данных, а параметризация не позволяет интерпретировать ввод как синтаксис SQL. Поведение драйверов на уровне протокола может различаться, поэтому не предполагайте, что все они передают значения одинаково. Параметры PostgreSQL не могут представлять имена таблиц или столбцов; выбирайте динамическую структуру запроса из фиксированного списка приложения.
Связывайте числовое значение и проверяйте его смысл
Если приложению нужен именно такой тип, проверьте, что ID — положительное безопасное целое число, но всё равно передавайте его как параметр запроса. Проверка защищает контракт входных данных приложения, а параметризация не позволяет входу стать синтаксисом SQL. Параметры PostgreSQL не заменяют имена таблиц или столбцов, поэтому выбирайте динамическую структуру запроса из фиксированного списка, заданного приложением.
const rawId = new URL(request.url).searchParams.get("id");
const result = await pool.query(
`SELECT id FROM users WHERE id = ${rawId}`
);
const rawId = new URL(request.url).searchParams.get("id");
if (rawId === null || !/^[0-9]+$/.test(rawId)) {
return new Response("Invalid id", { status: 400 });
}
const id = Number(rawId);
if (!Number.isSafeInteger(id) || id < 1) {
return new Response("Invalid id", { status: 400 });
}
const result = await pool.query(
"SELECT id FROM users WHERE id = $1",
Array.of(id)
);
Источники
- flawopen.com — SQL Injection (все языки)
- Что такое параметризованный запрос?
- node-postgres — Parameterized query API