flawopen.com/SQL-инъекция/Хранимые процедуры
Защищают ли хранимые процедуры от SQL-инъекций?
Нет — это распространённое заблуждение. Хранимая процедура защищает только при внутреннем связывании параметров. Если она собирает запрос конкатенацией входных значений в строку и выполняет её через EXEC или sp_executesql, риск такой же, как при конкатенации в приложении.
-- 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;
-- 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 поддерживает параметры: объявите их и передайте значения отдельно (например, EXEC sp_executesql @sql, N'@id INT', @id = @UserId). Не конкатенируйте значения в @sql. Для динамических имён таблиц и столбцов используйте строгий список допустимого: идентификаторы нельзя связать как параметры.