FlawOpen

flawopen.com/SQL-инъекция/Хранимые процедуры

Защищают ли хранимые процедуры от SQL-инъекций?

Справочная страница
Краткий ответ

Нет — это распространённое заблуждение. Хранимая процедура защищает только при внутреннем связывании параметров. Если она собирает запрос конкатенацией входных значений в строку и выполняет её через EXEC или sp_executesql, риск такой же, как при конкатенации в приложении.

НЕБЕЗОПАСНО — конкатенация значения в динамический SQL
-- SQL Server T-SQL; dbo.Users.Id is NVARCHAR(50).
CREATE PROCEDURE dbo.GetUser
  @UserId NVARCHAR(50)
AS
BEGIN
  DECLARE @sql NVARCHAR(MAX) =
    N'SELECT Id FROM dbo.Users WHERE Id = N'''
      + @UserId + N'''';
  EXEC(@sql);
END;
БЕЗОПАСНО — параметр через sp_executesql
-- SQL Server T-SQL; same illustrative schema.
CREATE PROCEDURE dbo.GetUser
  @UserId NVARCHAR(50)
AS
BEGIN
  DECLARE @sql NVARCHAR(MAX) =
    N'SELECT Id FROM dbo.Users WHERE Id = @id';
  EXEC sys.sp_executesql
    @stmt = @sql,
    @params = N'@id NVARCHAR(50)',
    @id = @UserId;
END;

Почему это заблуждение распространено

«Используйте хранимые процедуры» часто называют универсальным решением SQL-инъекций. Это верно, только если процедура передаёт значения как связанные параметры обычного запроса. Если она строит динамический SQL через EXEC и конкатенирует недоверенные значения, риск возвращается. Когда динамический SQL необходим, связывайте значения через sp_executesql. Имена таблиц и столбцов нельзя передать как значения-параметры; сопоставляйте разрешённые варианты с фиксированными идентификаторами через строгий список допустимого.

Часто задаваемые вопросы

Может ли sp_executesql быть безопасным?

Да. sp_executesql поддерживает параметры: объявите их и передайте значения отдельно (например, EXEC sp_executesql @sql, N'@id INT', @id = @UserId). Не конкатенируйте значения в @sql. Для динамических имён таблиц и столбцов используйте строгий список допустимого: идентификаторы нельзя связать как параметры.

Источники

См. также SQL-инъекции (CWE-89): как они работают и как их предотвратить в любом языке — flawopen.com Защищает ли TypeORM QueryBuilder от SQL-инъекций? Django ORM и SQL Injection: безопасные шаблоны SQL-инъекция в Doctrine ORM: безопасные запросы EF Core FromSqlRaw: безопасный SQL с параметрами FastAPI и SQL Injection: границы защиты Pydantic GORM Raw SQL: защита от SQL-инъекций в Go