¿Son los parámetros realmente suficientes para prevenir las inyecciones de SQL?

83

He estado predicando a mis colegas y aquí en SO sobre la bondad de usar parámetros en consultas SQL, especialmente en aplicaciones .NET. Incluso he ido tan lejos como para prometerles que darían inmunidad contra los ataques de inyección SQL.

Pero empiezo a preguntarme si esto realmente es cierto. ¿Existe algún ataque de inyección SQL conocido que tenga éxito contra una consulta parametrizada? ¿Puede, por ejemplo, enviar una cadena que provoque un desbordamiento del búfer en el servidor?

Por supuesto, hay otras consideraciones que hacer para garantizar que una aplicación web sea segura (como desinfectar la entrada del usuario y todo eso), pero ahora estoy pensando en inyecciones de SQL. Estoy especialmente interesado en los ataques contra MsSQL 2005 y 2008 ya que son mis bases de datos principales, pero todas las bases de datos son interesantes.

Editar: Para aclarar lo que quiero decir con parámetros y consultas parametrizadas. Al usar parámetros me refiero al uso de "variables" en lugar de construir la consulta sql en una cadena.
Entonces, en lugar de hacer esto:

SELECT * FROM Table WHERE Name = 'a name'

Nosotros hacemos esto:

SELECT * FROM Table WHERE Name = @Name

y luego establezca el valor del parámetro @Name en el objeto de consulta / comando.

Runa Grimstad
fuente
deberíamos aclarar qué se entiende por parámetros (como señaló Jonathan Leffler): estaba pensando en parámetros de procedimiento almacenado, pero también los hay? parms y {0} parms ...
Steven A. Lowe
Es mucho más fácil decirlo, no usamos la concatenación para construir una consulta.
Dado que la etiqueta es asp.net, supongo que está creando aplicaciones web. En este caso, también debe ocuparse de los ataques XSS, y tal vez de otros
Spikolynn

Respuestas:

50

Los marcadores de posición son suficientes para prevenir las inyecciones. Es posible que aún esté abierto a desbordamientos de búfer, pero ese es un tipo de ataque completamente diferente de una inyección SQL (el vector de ataque no sería la sintaxis SQL sino binario). Dado que todos los parámetros pasados ​​se escaparán correctamente, no hay forma de que un atacante pase datos que serán tratados como SQL "en vivo".

No puede usar funciones dentro de marcadores de posición, y no puede usar marcadores de posición como nombres de columnas o tablas, porque se escapan y se citan como cadenas literales.

Sin embargo, si usa parámetros como parte de una concatenación de cadenas dentro de su consulta dinámica, aún es vulnerable a la inyección, porque sus cadenas no se escaparán sino que serán literales. El uso de otros tipos de parámetros (como un número entero) es seguro.

Dicho esto, si está utilizando use input para establecer el valor de algo como security_level, entonces alguien podría convertirse en administradores en su sistema y tener un libre para todos. Pero eso es solo una validación de entrada básica y no tiene nada que ver con la inyección SQL.

Adam Bellaire
fuente
El punto clave es comprender el problema planteado por la respuesta de Steve Lowe, también señalado en el artículo que cita @mikekidder: debe tener cuidado donde sea que esté el SQL dinámico, ya sea en la aplicación o en el servidor. El SQL dinámico es peligroso, pero puede protegerse.
Jonathan Leffler
"No hay forma de que un atacante pase datos que serán tratados como SQL 'en vivo'". - Esto no es del todo cierto, consulte los ejemplos a continuación.
Booji Boy
Todos los ejemplos siguientes definen "consulta parametrizada" para referirse al código SQL que acepta parámetros. La definición normal es una consulta que usa su colección de parámetros DBMS. Salvo un error de DBMS, esta última técnica evita la inyección de SQL.
HTTP 410
2
He leído todos y cada uno de los enlaces. Cite cualquier enlace que se refiera a un ataque de inyección en funcionamiento contra la colección de parámetros DBMS. De hecho, el enlace que publicó se refiere específicamente a este enfoque como anulación de la inyección de SQL (consulte la sección "Uso de parámetros de SQL con seguridad de tipos").
HTTP 410
¡Hola! ¿Podría proporcionar un enlace a la gramática de Oracle SQL o algo por el estilo para probar esa respuesta? Lo entiendo y estoy absolutamente de acuerdo con usted, pero sería genial tener un enlace oficial a la documentación, gramática, etc. BestRegards, Raimbek
Raimbek Rakhimbek
13

No, todavía existe el riesgo de inyección SQL cada vez que interpola datos no validados en una consulta SQL.

Los parámetros de consulta ayudan a evitar este riesgo al separar los valores literales de la sintaxis SQL.

'SELECT * FROM mytable WHERE colname = ?'

Eso está bien, pero hay otros propósitos de interpolar datos en una consulta SQL dinámica que no puede usar parámetros de consulta, porque no es un valor SQL sino un nombre de tabla, nombre de columna, expresión o alguna otra sintaxis.

'SELECT * FROM ' + @tablename + ' WHERE colname IN (' + @comma_list + ')'
' ORDER BY ' + @colname'

No importa si está utilizando procedimientos almacenados o ejecutando consultas SQL dinámicas directamente desde el código de la aplicación. El riesgo sigue ahí.

El remedio en estos casos es emplear FIEO según sea necesario:

  • Entrada de filtro: valide que los datos parezcan enteros legítimos, nombres de tablas, nombres de columnas, etc. antes de interpolarlos.

  • Salida de escape: en este caso, "salida" significa poner datos en una consulta SQL. Usamos funciones para transformar variables utilizadas como cadenas literales en una expresión SQL, de modo que las comillas y otros caracteres especiales dentro de la cadena se escapen. También deberíamos usar funciones para transformar variables que se usarían como nombres de tablas, nombres de columnas, etc. En cuanto a otras sintaxis, como escribir expresiones SQL completas de forma dinámica, ese es un problema más complejo.

Bill Karwin
fuente
12

Parece haber cierta confusión en este hilo sobre la definición de una "consulta parametrizada".

  • SQL, como un proceso almacenado que acepta parámetros.
  • SQL que se llama utilizando la colección de parámetros DBMS.

Dada la definición anterior, muchos de los enlaces muestran ataques en funcionamiento.

Pero la definición "normal" es la última. Dada esa definición, no conozco ningún ataque de inyección SQL que funcione. Eso no significa que no haya uno, pero aún no lo he visto.

De los comentarios, no me estoy expresando con la suficiente claridad, así que aquí hay un ejemplo que, con suerte, será más claro:

Este enfoque está abierto a la inyección SQL

exec dbo.MyStoredProc 'DodgyText'

Este enfoque no está abierto a la inyección de SQL

using (SqlCommand cmd = new SqlCommand("dbo.MyStoredProc", testConnection))
{
    cmd.CommandType = CommandType.StoredProcedure;
    SqlParameter newParam = new SqlParameter(paramName, SqlDbType.Varchar);
    newParam.Value = "DodgyText";
    .....
    cmd.Parameters.Add(newParam);
    .....
    cmd.ExecuteNonQuery();
}
HTTP 410
fuente
¿Puede aclarar qué quiere decir con la colección de parámetros DBMS en oposición a un procedimiento que acepta parámetros?
Rune Grimstad
Rune, lea la sección "Use Type-Safe SQL Parameters" de este enlace: msdn.microsoft.com/en-us/library/ms161953.aspx
HTTP 410
Mi respuesta fue a la pregunta original de Rune, antes de que fuera editada con la actualización.
mikekidder
He leído y releído ese artículo de msdn sobre inyección SQL y todavía no veo cómo hay una diferencia entre los parámetros que toma un procedimiento almacenado y los parámetros que toma una consulta dinámica. Aparte del hecho de que las consultas dinámicas son dinámicas. Todavía tienes que vincular los parámetros, ¿verdad?
Rune Grimstad
Es la unión lo que marca la diferencia. Si llama a un proceso almacenado con parámetros directamente, no se realiza ningún filtrado de entrada. Pero si enlaza (por ejemplo) utilizando la colección de parámetros SqlCommand en .NET, todos los parámetros se filtrarán y se tratarán como texto sin formato.
HTTP 410
10

cualquier parámetro sql de tipo cadena (varchar, nvarchar, etc.) que se utiliza para construir una consulta dinámica sigue siendo vulnerable

de lo contrario, la conversión del tipo de parámetro (por ejemplo, a int, decimal, date, etc.) debería eliminar cualquier intento de inyectar sql a través del parámetro

EDITAR: un ejemplo, donde el parámetro @ p1 está destinado a ser un nombre de tabla

create procedure dbo.uspBeAfraidBeVeryAfraid ( @p1 varchar(64) ) 
AS
    SET NOCOUNT ON
    declare @sql varchar(512)
    set @sql = 'select * from ' + @p1
    exec(@sql)
GO

Si se selecciona @ p1 de una lista desplegable, es un vector de ataque de inyección SQL potencial;

Si @ p1 se formula programáticamente sin la capacidad del usuario para intervenir, entonces no es un vector de ataque de inyección SQL potencial

Steven A. Lowe
fuente
No; el punto es que la cadena pasada al DBMS no es parte de la declaración SQL. Por lo tanto, el valor en la cadena no hace ninguna diferencia en la interpretación del SQL, solo en los valores referenciados por el SQL.
Jonathan Leffler
Así es como veo los parámetros también. Se supone que deben prevenir este problema.
Rune Grimstad
2
Steven tiene razón si, por ejemplo, está pasando una cadena a un sp que la usa para ejecutar algo como sp_executeSql (servidor SQL), entonces todavía tiene un riesgo de inyección SQL.
alexmac
@Steven: eso no es un parámetro para el SQL; tendría que tener un marcador de posición (signo de interrogación) en lugar de la concatenación de cadenas. Y SQL no le permite especificar el nombre de la tabla por marcador de posición. Esa es una vulnerabilidad pura de inyección de SQL: el problema original.
Jonathan Leffler
@Steven: tal vez el término 'parámetro' se haya sobrecargado una vez con demasiada frecuencia. : D
Jonathan Leffler
6

Un desbordamiento de búfer no es una inyección SQL.

Las consultas parametrizadas garantizan que está a salvo de la inyección SQL. No garantizan que no haya posibles exploits en forma de errores en su servidor SQL, pero nada lo garantizará.

Blorgbeard está fuera
fuente
2

Sus datos no están seguros si usa SQL dinámico de cualquier forma o forma porque los permisos deben estar a nivel de tabla. Sí, ha limitado el tipo y la cantidad de ataque de inyección de esa consulta en particular, pero no ha limitado el acceso que un usuario puede obtener si encuentra una manera de ingresar al sistema y usted es completamente vulnerable a los usuarios internos que acceden a lo que no deberían. para cometer fraude o robar información personal para vender. El SQL dinámico de cualquier tipo es una práctica peligrosa. Si utiliza procesos almacenados no dinámicos, puede establecer permisos en el nivel de proceso y ningún usuario puede hacer nada excepto lo definido por los procesos (excepto los administradores del sistema, por supuesto).

HLGEM
fuente
así que la lección aquí es que si debe usar SQL dinámico, hágalo solo dentro de un procedimiento almacenado. +1 buen consejo!
Steven A. Lowe
1
No, el SQL dinámico en los procesos almacenados aún puede introducir fallas de inyección de SQL, al interpolar datos no validados en la consulta dinámica.
Bill Karwin
No, la lección aquí es nunca usar SQl dinámico
HLGEM
@HLGEM: correcto, y los automóviles están involucrados en accidentes de tráfico, por lo que nunca deberíamos usarlos.
Bill Karwin
Pero el SQL dinámico en un proceso almacenado se ejecuta (de forma predeterminada) con el permiso de la persona que llama, no como el SQL estático que se ejecuta con el permiso del propietario del proceso almacenado. Esta es una distinción importante.
HTTP 410
1

Es posible que un proceso almacenado sea vulnerable a tipos especiales de inyección SQL a través de desbordamiento / truncamiento, consulte: Inyección habilitada por truncamiento de datos aquí:

http://msdn.microsoft.com/en-us/library/ms161953.aspx

Chico Booji
fuente
Si lee el artículo en detalle, verá que el uso de la colección de parámetros de SQL Server previene este ataque. Y esa es la definición normal de una "consulta parametrizada": utiliza la colección de parámetros del DBMS.
HTTP 410
1

Solo recuerde que con los parámetros puede almacenar fácilmente la cadena, o decir nombre de usuario si no tiene ninguna política, "); eliminar usuarios de la tabla; -"

Esto en sí mismo no causará ningún daño, pero es mejor que sepa dónde y cómo se usa esa fecha más adelante en su aplicación (por ejemplo, almacenada en una cookie, recuperada más tarde para hacer otras cosas).

nos
fuente
1

Puede ejecutar sql dinámico como ejemplo

DECLARE @SQL NVARCHAR(4000);
DECLARE @ParameterDefinition NVARCHAR(4000);

SELECT  @ParameterDefinition = '@date varchar(10)'

SET @SQL='Select CAST(@date AS DATETIME) Date'

EXEC sp_executeSQL @SQL,@ParameterDefinition,@date='04/15/2011'
Mohamed Abbas
fuente