Избегание риска SQL-инъекций
Вы можете избежать риска SQL-инъекций, передавая значения параметров SQL в качестве аргументов функций пакета
sql. Многие функции пакета sql предоставляют параметры для SQL-запроса и значения,
которые будут использоваться в параметрах этого запроса (другие предоставляют параметр для подготовленного
запроса и параметры).
Код в следующем примере использует символ ? в качестве заполнителя для параметра id,
который передается как аргумент функции:
<code>// Корректный формат выполнения SQL-запроса с параметрами.
rows, err := db.Query("SELECT * FROM user WHERE id = ?", id)
</code>
Функции пакета sql, выполняющие операции с базой данных, создают подготовленные запросы из
переданных вами аргументов. Во время выполнения пакет sql преобразует SQL-запрос в подготовленный
запрос и отправляет его вместе с параметром, который передаётся отдельно.
Примечание: Заполнители параметров могут различаться в зависимости от используемой СУБД и
драйвера. Например, драйвер pq для Postgres принимает форму заполнителя вида
$1 вместо ?.
Вы можете быть соблазнены использовать функцию из пакета fmt для сборки SQL-запроса в виде строки с
включенными параметрами — например, так:
<code>// РИСК БЕЗОПАСНОСТИ!
rows, err := db.Query(fmt.Sprintf("SELECT * FROM user WHERE id = %s", id))
</code>
Это небезопасно! Когда вы делаете это, Go собирает весь SQL-запрос, заменяя форматный спецификатор
%s значением параметра, прежде чем отправить полный запрос в СУБД. Это создаёт риск
SQL-инъекции,
поскольку вызывающий код может передать неожиданный фрагмент SQL в качестве аргумента id. Этот
фрагмент может завершить SQL-запрос неожиданным образом, что представляет опасность для вашего приложения.
Например, передавая определённое значение %s, можно получить следующий результат, который может
вернуть все записи пользователей из вашей базы данных:
<code>SELECT * FROM user WHERE id = 1 OR 1=1; </code>