flawopen.com/Inyección SQL/Procedimientos almacenados
¿Los procedimientos almacenados evitan la inyección SQL?
No; es una idea equivocada muy común. Un procedimiento almacenado protege solo si usa parámetros enlazados internamente. Si concatena sus entradas en una cadena de consulta y la ejecuta con EXEC o sp_executesql, es tan vulnerable como concatenar cadenas en la aplicación.
-- 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;
Por qué es común esta idea equivocada
“Usa procedimientos almacenados” suele repetirse como solución general a la inyección SQL. Funciona si el procedimiento pasa los valores como parámetros enlazados en una consulta normal. Si construye SQL dinámico con EXEC y concatena valores no confiables, reintroduce el mismo riesgo. Cuando el SQL dinámico sea necesario, enlaza valores con sp_executesql. Los nombres de tablas y columnas no se pueden enlazar como valores; asigna las opciones permitidas a identificadores fijos mediante una lista de permitidos.
Preguntas frecuentes
Sí. sp_executesql admite parámetros: decláralos y pasa los valores por separado (por ejemplo, EXEC sp_executesql @sql, N'@id INT', @id = @UserId). No concatentes valores en @sql. Para nombres dinámicos de tabla o columna, usa una lista de permitidos estricta porque los identificadores no son parámetros enlazables.