Cómo asegurar procedimientos almacenados contra inyecciones SQL

Aunque los procedimientos almacenados de SQL Server ayudan con la seguridad el código ocultando la implementación de lógica de negocios e incluso protegiendo contra algunos tipos de ataques de inyección SQL – primariamente aquellos que usan operadores como AND o OR para enviar comandos a un valor de parámetros de entrada válido, simplemente envolver el código en un procedimiento almacenado no significa que las aplicaciones, bases de datos y Servidores SQL están a salvo de todo tipo de ataques de inyección SQL. Así que, ¡cómo crear procedimientos almacenados a prueba de inyecciones SQL?

Consideremos el siguiente procedimiento almacenado:

CREATE PROCEDURE usp_GetEmployee @employeeName varchar(50) = NULL AS
DECLARE @sql nvarchar(4000)
SELECT @sql = ' SELECT EmployeeMiddleName, EmployeeSurname, SSN ' +
              ' FROM HumanResources.Employee ' +
              ' WHERE '
IF @employeeName IS NOT NULL
   SELECT @sql = @sql + ' employeeName LIKE ''' + @employeeName + ''''
EXEC (@sql)

El valor para la variable @employeeName es directamente tomado de lo que haya ingresado el usuario concatenado con el contenido de la variable@sql. Adicionalmente, el comandoEXEC , el cual toma una cadena como parámetro y la ejecuta como una sentencia SQL, está siendo usado. Por tanto, el procedimiento almacenado anterior es todavía vulnerable a una inyección SQL aun cuando las entradas del usuario son pasadas como parámetros. La razón para esto es que la entrada del usuario está encerrada en comillas simples y concatenada a una cadena para formar la consulta SQL. En lugar de que el parámetro sea una cadena de búsqueda para la consulta SQL, la entrada del usuario se ha convertido en parte de la consulta en sí misma ya que está encerrada entre comillas simples:

Por tanto, si el usuario ingresa:

'1' OR '1'='1';EXEC master.dbo.xp_cmdshell 'dir'--'

Entonces la consulta SQL real, ejecutada en el servidor, será:

SELECT EmployeeMiddleName, EmployeeSurname, SSN
FROM HumanResources.Employee
WHERE employeeName LIKE '1' OR '1'='1';EXEC master.dbo.xp_cmdshell 'dir'--'

Lo que resultará en retornar todas las filas de la tabla, así como ejecutar el comando de Windows DIR.

La manera más rápida de asegurar que todos los procedimientos almacenados estén seguros de inyecciones SQL es usar ApexSQL Refactor.

ApexSQL Refactor es un complemento para SQL Server Management Studio y Visual Studio el cual formatea y refactoriza código SQL usando 11 refactorizaciones de código y más de 160 opciones de formato. Expande comodines, completa nombres de objetos, renombra objetos de bases de datos SQL y parámetros sin romper dependencias y mucho más.

Para asegurar los procedimientos almacenados de ataques de inyección SQL:

  1. Abra el procedimiento almacenado para editar ya sea en SQL Server Management Studio o Visual Studio
  2. Seleccione el cuerpo del procedimiento almacenado
  3. En el menú ApexSQL, haga clic en ApexSQL Refactor
  4. Seleccione la opción Encapsulate code as -> Stored procedure option

    Encapsulate code as - Stored procedure option

  5. En el campo Name ingrese un nuevo nombre para el procedimiento almacenado y especifique su esquema usando el menú desplegable Schema
  6. Haga en el botón Generate preview para previsualizar cómo el código será modificado:

    Encapsulate code as a stored procedure dialog

  7. Haga clic en el botón Encapsulate para asegurar el procedimiento almacenado

Por ejemplo, el procedimiento almacenado no seguro considerado al principio de este artículo será encapsulado como:

CREATE PROCEDURE dbo.usp_GetEmployeeSafe(@employeeName SQL_VARIANT)
AS
BEGIN
DECLARE @sql nvarchar(4000)
SELECT @sql = ' SELECT EmployeeMiddleName, EmployeeSurname, SSN ' +
              ' FROM HumanResources.Employee ' +
              ' WHERE '
IF @employeeName IS NOT NULL
   SELECT @sql = @sql + ' employeeName LIKE @employeeName '
EXEC sp_executesql @sql,N'@employeeName varchar(50)', @employeeName
END
GO

De esta manera la entrada del usuario no es encerrada dentro de comillas simples. Más bien, es pasada como parámetros a la sentencia SQL. Adicionalmente, sp_executesql está siendo usado para ejecutar con la lista de parámetros y las sentencias SQL parametrizadas. La diferencia entre EXEC y sp_executesql es que la primera trata el parámetro de cadena como una sentencia SQL mientras que el último es un procedimiento de sistema cuyo primer parámetros es una sentencia SQL parametrizada y el segundo parámetro es una declaración de parámetro-lista, similar a la lista de parámetros presente en la declaración de un procedimiento almacenado y todo lo que queda son simplemente los parámetros en ese parámetro-lista. Así que la consulta SQL construida usando este método es siempre la misma a pesar de cómo es llamada o a pesar de la entrada del usuario en tiempo de ejecución. Si un usuario malicioso ingresa algo junto a las líneas:

'1' OR '1'='1'

Simplemente serán pasadas como un parámetro a la sentencia SQL y no será parte de una sentencia SQL en sí misma, por tanto haciendo al procedimiento almacenado invulnerable a ataques de inyección SQL.

Traductor: Daniel Calbimonte

noviembre 14, 2015