¿Qué función cita un identificador en dynamic-sql con SQL Server?

11

¿Cuál es el método de SQL Server para identificar identificadores de forma segura para la generación dinámica de SQL?

¿Cómo me aseguro de que, dado un nombre de columna generado dinámicamente para una declaración generada dinámicamente, la columna en sí no sea un ataque de inyección SQL?

Digamos que tengo una instrucción SQL,

SELECT [$col] FROM table;

que es esencialmente lo mismo que

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

Qué detiene un ataque de inyección donde

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

Resultando en

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

Respuestas:

14

¡La función que estás buscando es QUOTENAME!

Mediante el uso práctico de la tecnología de corchetes, puede encapsular cadenas de forma segura para ayudar en la prevención de ataques de inyección SQL en caliente.

Tenga en cuenta que el simple hecho de poner corchetes alrededor de algo no lo cita con seguridad, aunque puede evitar que su código se equivoque con caracteres no válidos en los nombres de los objetos.

Buen código

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

Código malo

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

Para dar un ejemplo específico ...

Lo siguiente funciona bien para la entrada inicial

DECLARE @ObjectName SYSNAME = 'sysobjects';

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

EXEC (@dynSql);

Pero con entrada maliciosa es vulnerable a la inyección 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);

El uso QUOTENAMEse escapa correctamente de la incrustación ]y evita que ocurra el intento de inyección 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 ' + QUOTENAME(@ObjectName);

EXEC (@dynSql);

Nombre de objeto no válido 'sysobjects]; SELECT' Este es un código arbitrario ejecutado. Podría haber caído una tabla o otorgado permisos '-'.

Erik Darling
fuente