web-dev-qa-db-fra.com

Procédure stockée EXEC vs différence sp_executesql?

J'ai écrit deux procédures stockées dont une avec sp_executesql et d'autres n'ont pas sp_executesql les deux exécutent correctement les mêmes résultats, je n'ai pas compris quelle est la différence ici entre

EXEC (@SQL) vs EXEC sp_executesql @SQL, N '@ eStatus varchar (12)', @eStatus = @Status

et comment EXEC (@SQL) est sujet à l'injection SQL et sp_executesql @SQL ...... ne l'est pas?

Procédure stockée ci-dessous sans sp_executesql

ALTER proc USP_GetEmpByStatus
(
@Status varchar(12)
)
AS
BEGIN
DECLARE @TableName AS sysname = 'Employee'
Declare @Columns as sysname = '*'
DECLARE @SQL as nvarchar(128) = 'select ' + @Columns + ' from ' + @TableName + ' where Status=' + char(39) + @Status + char(39)
print (@SQL)
EXEC (@SQL)
END

EXEC USP_GetEmpByStatus 'Active'

Procédure stockée ci-dessous avec sp_executesql

create proc USP_GetEmpByStatusWithSpExcute
(
@Status varchar(12)
)
AS
BEGIN
DECLARE @TableName AS sysname = 'JProCo.dbo.Employee'
Declare @Columns as sysname = '*'
DECLARE @SQL as nvarchar(128) = 'select ' + @Columns + ' from ' + @TableName + ' where Status=' + char(39) + @Status + char(39)
print @SQL
exec sp_executesql @SQL, N'@eStatus varchar(12)', @eStatus = @Status
END

EXEC USP_GetEmpByStatusWithSpExcute 'Active'
25
Registered User

Votre sp_executesql SQL devrait probablement l'être;

DECLARE @SQL as nvarchar(128) = 'select ' + @Columns + ' from ' + 
            @TableName + ' where Status=@eStatus'

Cela vous permettra d'appeler sp_executesql avec @eStatus comme paramètre au lieu de l'intégrer dans le SQL. Cela donnera l'avantage que @eStatus peut contenir tous les caractères et il sera correctement correctement échappé automatiquement par la base de données si nécessaire pour être sécurisé.

Comparez cela au SQL requis pour EXEC ;

DECLARE @SQL as nvarchar(128) = 'select ' + @Columns + ' from ' + 
            @TableName + ' where Status=' + char(39) + @Status + char(39)

... où un caractère (39) intégré dans @Status rendra votre SQL invalide et créera éventuellement une possibilité d'injection SQL. Par exemple, si @Status est défini sur O'Reilly, votre SQL résultant serait;

select acol,bcol,ccol FROM myTable WHERE Status='O'Reilly'
19
Joachim Isaksson

Outre l'utilisation, il existe quelques différences importantes:

  1. sp_executesql permet de paramétrer les instructions Par conséquent, il est plus sûr que EXEC en termes d'injection SQL

  2. sp_executesql peut tirer parti des plans de requête mis en cache. La chaîne TSQL n'est générée qu'une seule fois, après quoi chaque fois qu'une même requête est appelée avec sp_executesql, SQL Server récupère le plan de requête du cache et le réutilise

  3. Les tables temporaires créées dans EXEC ne peuvent pas utiliser le mécanisme de mise en cache des tables temporaires

19
FLICKER

Avec sp_executesql, vous n'avez pas besoin de construire votre requête comme ça. Vous pouvez le déclarer comme ceci:

DECLARE @SQL as nvarchar(128) = 'select ' + @Columns + ' from ' + 
@TableName + ' where Status=@eStatus'

De cette façon, si votre @Status la valeur provient d'un utilisateur que vous pouvez utiliser @eStatus et ne pas avoir à vous soucier de vous échapper '. sp_executesql vous donne la possibilité de mettre des variables dans votre requête sous forme de chaîne, au lieu d'utiliser la concaténation. Vous avez donc moins à vous soucier.

Les variables de colonne et de table sont toujours les mêmes, mais il est moins probable qu'elles proviennent directement d'un utilisateur.

4
JeffB

Avec Exec Vous ne pouvez pas avoir un espace réservé dans votre chaîne d'instruction T-Sql.

sp_executesql vous donne l'avantage d'avoir un espace réservé et de passer la valeur réelle à runtime

2
Mohammadreza