FlawOpen

flawopen.com/Injeção de SQL/Procedimentos armazenados

Procedimentos armazenados evitam SQL injection?

Página de referência
Resposta curta

Não — isso é um equívoco comum. Um procedimento armazenado protege você apenas se usar vinculação de parâmetros internamente. Se montar a consulta concatenando entradas em uma string e executá-la com EXEC ou sp_executesql, o risco é o mesmo da concatenação na aplicação.

INSEGURO — concatena o valor no SQL dinâmico
-- 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;
SEGURO — vincula um parâmetro com 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;

Por que esse equívoco é comum

“Use procedimentos armazenados” costuma ser apresentado como solução geral para SQL injection. Isso funciona quando o procedimento passa valores como parâmetros vinculados em uma consulta normal. Se construir SQL dinâmico com EXEC e concatenar valores não confiáveis, recria o mesmo risco. Quando SQL dinâmico for necessário, vincule os valores com sp_executesql. Nomes de tabelas ou colunas não podem ser vinculados como valores; mapeie as opções permitidas para identificadores fixos por meio de uma allowlist.

Perguntas frequentes

sp_executesql pode ser seguro?

Sim. sp_executesql aceita parâmetros: declare-os e passe os valores separadamente (por exemplo, EXEC sp_executesql @sql, N'@id INT', @id = @UserId). Não concatene valores em @sql. Para nomes dinâmicos de tabela ou coluna, use uma allowlist estrita, pois identificadores não são parâmetros vinculáveis.

Referências

Veja também SQL Injection (CWE-89): como funciona e como evitar em todas as linguagens — flawopen.com O QueryBuilder do TypeORM é seguro contra SQL Injection? Django ORM e SQL Injection: padrões seguros Injeção SQL no Doctrine ORM: consultas seguras EF Core FromSqlRaw: SQL parametrizado seguro FastAPI e SQL Injection: o que o Pydantic protege GORM Raw SQL: evite injeção SQL em Go