Quelle fonction cite un identificateur dans dynamic-sql avec SQL Server?

11

Quelle est la méthode SQL Server de citation sûre des identificateurs pour la génération dynamique de SQL.

Comment garantir un nom de colonne généré dynamiquement pour une instruction générée dynamiquement que la colonne elle-même n'est pas une attaque par injection SQL.

Disons que j'ai une instruction SQL,

SELECT [$col] FROM table;

qui est essentiellement le même que

'SELECT [' + $col + '] FROM table;'

Qu'est-ce qui arrête une attaque par injection où

$col = "name] FROM sys.objects; \r\n DROP TABLE my.accounts; \r\n\ --";

Résultant en

SELECT [name] FROM sys.objects;
DROP TABLE my.accounts;
-- ] FROM table;
Evan Carroll
la source

Réponses:

14

La fonction que vous recherchez est QUOTENAME!

Grâce à l'utilisation pratique de la technologie des crochets, vous pouvez encapsuler en toute sécurité des chaînes pour aider à prévenir les attaques par injection SQL à chaud.

Notez que le simple fait de coller des crochets autour de quelque chose ne le cite pas en toute sécurité, bien que vous puissiez éviter que votre code ne comporte des erreurs avec des caractères non valides dans les noms d'objets.

Bon code

DECLARE @sql NVARCHAR(MAX) = N''
SELECT @sql = 'SELECT ' + QUOTENAME(d.name) + ' FROM your_mom'
FROM sys.databases AS d

Mauvais code

DECLARE @sql NVARCHAR(MAX) = N''
SELECT @sql = 'SELECT [' + d.name + '] FROM your_mom'
FROM sys.databases AS d

Pour donner un exemple précis ...

Ce qui suit fonctionne bien pour l'entrée initiale

DECLARE @ObjectName SYSNAME = 'sysobjects';

DECLARE @dynSql NVARCHAR(MAX) = 'SELECT COUNT(*) FROM [' + @ObjectName + ']';

EXEC (@dynSql);

Mais avec une entrée malveillante, il est vulnérable à l'injection SQL

DECLARE @ObjectName SYSNAME = 'sysobjects];SELECT ''This is some arbitrary code executed. It might have dropped a table or granted permissions''--'

DECLARE @dynSql NVARCHAR(MAX) = 'SELECT  COUNT(*)  FROM [' + @ObjectName + ']';

EXEC (@dynSql);

L'utilisation QUOTENAMEcorrecte échappe à l'embarqué ]et empêche la tentative d'injection SQL de se produire.

DECLARE @ObjectName SYSNAME = 'sysobjects];SELECT ''This is some arbitrary code executed. It might have dropped a table or granted permissions''--'

DECLARE @dynSql NVARCHAR(MAX) = 'SELECT  COUNT(*)  FROM ' + QUOTENAME(@ObjectName);

EXEC (@dynSql);

Nom d'objet non valide 'sysobjects]; SELECT' Il s'agit d'un code arbitraire exécuté. Il a peut-être supprimé une table ou accordé des autorisations «-».

Erik Darling
la source