Как защититься от SQL-инъекций
golangSQL-инъекциибазы данныхбезопасностьразработка
Что проверяют
Знаете ли вы единственно правильный способ и понимаете ли, что экранирование руками им не является.
Как отвечать
Главное правило: данные никогда не склеиваются со строкой запроса. Используются параметризованные запросы, где база получает шаблон и значения отдельно.
// опасно: значение попадает в текст запроса
db.Query("select * from users where email = '" + email + "'")
// правильно: значение передаётся параметром
db.QueryContext(ctx, "select id, name from users where email = $1", email)Так значение никогда не интерпретируется как часть запроса, независимо от содержимого. В Go это работает и в database/sql, и в pgx, и в конструкторах запросов вроде Squirrel.
Что ещё стоит назвать:
- имена таблиц и колонок параметром не передаются. Если сортировка или фильтр приходят от клиента, значение сверяется с белым списком допустимых имён, а не подставляется в текст;
LIKE: параметр подставляется целиком со знаками процента, а сами знаки в пользовательском вводе экранируются, иначе получится неожиданный шаблон;- ORM не защищает автоматически: сырые куски запроса и конструкции вроде
Rawуязвимы так же; - дополнительные рубежи: минимальные права у пользователя базы (никакого суперпользователя для приложения), проверка входных данных по формату, ограничение возвращаемого объёма, отсутствие текста ошибок базы в ответе клиенту;
- проверка: статические анализаторы и
go vetловят часть склеек, а линтер вродеsqlclosecheckзаодно ловит незакрытые строки результата.
Где спотыкаются
Экранируют кавычки вручную и считают это защитой.
Собирают динамический запрос из фильтров склейкой, оставляя дыру именно там.
Отдают клиенту текст ошибки базы, помогая атакующему подобрать запрос.