Определите причину по журналу API с синтаксической ошибкой SQL из параметра запроса
Сработал алерт на всплеск HTTP 500 с одной точки. Вот запись журнала за ним.
Ограничения:
ref— параметр строки запроса, присланный клиентом- клиент получил ровно это же тело ответа 500
- первая мысль команды — добавить фильтрацию ввода на периметре
2026-03-04T11:22:09Z ERROR api.orders psycopg2.errors.SyntaxError:
syntax error at or near "'"
LINE 1: ...FROM orders WHERE customer_ref = 'AC-1042'' ORDER BY created_at
request_id=8f1e path=/api/orders query=ref=AC-1042%27 status=500
response_body=stack trace + failing SQL statement returned to client
Определите причину и скажите, что нужно исправить.
Кавычка из параметра дошла до парсера SQL и досрочно закрыла литерал — значит, запрос склеен, и перед нами SQL-инъекция, а не плохой ввод. Чинить надо оба дефекта: связать ref параметром и убрать ошибку драйвера из ответа.
- ✗Читать синтаксическую ошибку как плохой ввод, а не как доказательство склейки
- ✗Чинить только утёкшую трассировку, оставляя запрос склеенным
- ✗Считать фильтрацию параметра на периметре устранением первопричины
- →Почему подавление ошибки усложняет поиск дыры, но не делает её безопаснее?
- →Что искать в кодовой базе, чтобы найти соседние запросы, собранные так же?
Что говорит журнал
syntax error at or near "'" и строка customer_ref = 'AC-1042'' означают, что кавычка из ref (%27) попала внутрь текста запроса и закрыла строковый литерал раньше времени. Параметризованный запрос так сломаться не может: там значение никогда не участвует в разборе. Значит, запрос собирается склейкой — точка уязвима для SQL-инъекции.
Второй дефект виден в response_body: трассировка и сам SQL уходят клиенту, раскрывая схему и подтверждая инъекцию без единой догадки.
Что чинить
# было — значение попадает в текст запроса
cur.execute(f"SELECT * FROM orders WHERE customer_ref = '{ref}' ORDER BY created_at")
# стало — значение связано, парсер видит только плейсхолдер
cur.execute(
"SELECT * FROM orders WHERE customer_ref = %s ORDER BY created_at",
(ref,),
)
Плюс обработчик ошибок отдаёт клиенту общий 500 с request_id, а подробности пишет только в журнал. Фильтрация ref на периметре — полезный дополнительный слой, но не устранение причины.