vinculo quoted_identifier que identificador datos ansi_nulls sql-server security tsql sql-injection sanitization

sql-server - que - sql server quoted_identifier



¿Cómo se puede vencer el saneamiento que escapa de las comillas simples mediante inyección SQL en SQL Server? (6)

Con algunas estipulaciones adicionales, su enfoque anterior no es vulnerable a la inyección de SQL. El principal vector de ataque a considerar es SQL Smuggling. El contrabando de SQL ocurre cuando los caracteres Unicode similares se traducen de manera inesperada (por ejemplo, `cambiando a ''). Hay varias ubicaciones donde una pila de aplicaciones podría ser vulnerable al contrabando de SQL.

  • ¿El lenguaje de programación maneja las cadenas de unicode apropiadamente? Si el lenguaje no es unicode, puede identificar mal un byte en un carácter Unicode como una comilla simple y escapar de él.

  • ¿La biblioteca de la base de datos del cliente (por ejemplo, ODBC, etc.) maneja las cadenas de unicode apropiadamente? System.Data.SqlClient en .Net framework, pero ¿qué hay de las antiguas bibliotecas de Windows 95? Las bibliotecas ODBC de terceros realmente existen. ¿Qué sucede si el controlador ODBC no admite Unicode en la cadena de consulta?

  • ¿El DB maneja la entrada correctamente? Las versiones modernas de SQL son inmune asumiendo que estás usando N '''', pero ¿qué pasa con SQL 6.5? SQL 7.0? No estoy al tanto de ninguna vulnerabilidad en particular, sin embargo, esto no estaba en el radar para los desarrolladores en la década de 1990.

  • Buffer se desborda? Otra preocupación es que la cadena citada es más larga que la cadena original. ¿En qué versión de Sql Server se introdujo el límite de 2 GB para entrada? Antes de eso, ¿cuál era el límite? En versiones anteriores de SQL, ¿qué sucedió cuando una consulta excedió el límite? ¿Existe algún límite en la longitud de una consulta desde el punto de vista de la biblioteca de red? ¿O en la longitud de la cadena en el lenguaje de programación?

  • ¿Hay alguna configuración de idioma que afecte la comparación utilizada en la función Reemplazar ()? .Net siempre hace una comparación binaria para la función Replace (). ¿Siempre será ese el caso? ¿Qué sucede si una versión futura de .NET admite anular ese comportamiento en el nivel de app.config? ¿Qué sucede si utilizamos una expresión regular en lugar de Reemplazar () para insertar una comilla simple? ¿La configuración regional de la computadora afecta esta comparación? Si ocurriera un cambio en el comportamiento, podría no ser vulnerable a la inyección de sql, sin embargo, puede haber editado inadvertidamente la cadena cambiando un carácter de código único que parecía una comilla simple en una comilla simple antes de llegar al DB.

Por lo tanto, suponiendo que está utilizando la función System.String.Replace () en C # en la versión actual de .Net con la biblioteca SqlClient incorporada en una versión actual (2005-2012) del servidor SQL, entonces su enfoque no es vulnerable. Cuando comienzas a cambiar las cosas, entonces no se pueden hacer promesas. El enfoque de consulta parametrizada es el enfoque correcto para la eficiencia, el rendimiento y (en algunos casos) la seguridad.

ADVERTENCIA Los comentarios anteriores no avalan esta técnica. Hay varias otras muy buenas razones por las cuales este es el enfoque incorrecto para generar SQL. Sin embargo, detallarlos está fuera del alcance de esta pregunta.

NO USE ESTA TÉCNICA PARA NUEVO DESARROLLO.

NO USE ESTA TÉCNICA PARA NUEVO DESARROLLO.

NO USE ESTA TÉCNICA PARA NUEVO DESARROLLO.

Para comenzar, soy consciente de que las consultas parametrizadas son la mejor opción, pero me pregunto qué hace vulnerable a la estrategia que presento a continuación. La gente insiste en que la siguiente solución no funciona, por lo que busco un ejemplo de por qué no lo haría.

Si SQL dinámico está integrado en código utilizando el siguiente escape antes de ser enviado a un servidor SQL, ¿qué tipo de inyección puede vencer esto?

string userInput= "N''" + userInput.Replace("''", "''''") + "''"

here se respondió una pregunta similar, pero no creo que ninguna de las respuestas sea aplicable aquí.

Escapar la comilla simple con una "/" no es posible en SQL Server.

Creo que SQL Smuggling con Unicode (descrito here ) se vería frustrado por el hecho de que la cadena que se está produciendo está marcada como Unicode por la N que precede a la comilla simple. Por lo que yo sé, no hay otros juegos de caracteres que SQL Server traduzca automáticamente a una sola cotización. Sin una cita única no escapada, no creo que la inyección sea posible.

No creo que String Truncation sea ​​tampoco un vector viable. SQL Server ciertamente no hará el truncamiento ya que el tamaño máximo para un nvarchar es de 2GB según Microsoft . Una cadena de 2 GB es inviable en la mayoría de las situaciones, e imposible en la mía.

La inyección de segundo orden podría ser posible, pero ¿es posible si:

  1. Todos los datos que entran en la base de datos se desinfectan utilizando el método anterior
  2. Los valores de la base de datos nunca se añaden al SQL dinámico (¿por qué lo harías de todos modos, cuando solo puedes hacer referencia al valor de la tabla en la parte estática de cualquier cadena SQL dinámica?).

No estoy sugiriendo que esto sea mejor o una alternativa al uso de consultas parametrizadas, pero quiero saber cómo lo que describí es vulnerable. ¿Algunas ideas?


Hay algunos casos donde esta función de escape fallará. El más obvio es cuando no se usa una sola cotización:

string table= "/"" + table.Replace("''", "''''") + "/"" string var= "`" + var.Replace("''", "''''") + "`" string index= " " + index.Replace("''", "''''") + " " string query = "select * from `"+table+"` where name=/""+var+"/" or id="+index

En este caso, puede "romper" usando una comilla doble, una marca de retroceso. En el último caso, no hay nada de lo que "se pueda escapar", por lo que puede escribir 1 union select password from users-- o la carga útil sql que desee el atacante.

La siguiente condición en la que fallará esta función de escape es si se toma una subcadena después de que se haya escapado la cadena (y , he encontrado vulnerabilidades como esta en la naturaleza):

string userPassword= userPassword.Replace("''", "''''") string userName= userInput.Replace("''", "''''") userName = substr(userName,0,10) string query = "select * from users where name=''"+userName+"'' and password=''"+userPassword+"''";

En este caso, un nombre de usuario de abcdefgji'' se convertirá en abcdefgji'''' mediante la función de escape y luego se vuelve a abcdefgji'' tomando la abcdefgji'' . Esto puede explotarse estableciendo el valor de la contraseña en cualquier instrucción sql, en este caso or 1=1-- se interpretaría como sql y el nombre de usuario se interpretaría como abcdefgji'''' and password= . La consulta resultante es la siguiente:

select * from users where name=''abcdefgji'''' and password='' or 1=1--

T-SQL y otras técnicas avanzadas de inyección de SQL están ya mencionadas. Inyección avanzada de SQL en aplicaciones de SQL Server es un excelente documento y debería leerlo si aún no lo ha hecho.

El último problema son los ataques Unicode. Esta clase de vulnerabilidades surge porque la función de escape no tiene conocimiento de la codificación mulit-byte, y esto puede ser utilizado por un atacante para "consumir" el carácter de escape . El anteponer una "N" a la cadena no ayudará, ya que esto no afecta el valor de los caracteres multi-byte más adelante en la cadena. Sin embargo, este tipo de ataque es muy poco común porque la base de datos debe estar configurada para aceptar cadenas unicode GBK (y no estoy seguro de que MS-SQL pueda hacer esto).

La inyección de código de segundo orden aún es posible; este patrón de ataque se crea al confiar en las fuentes de datos controladas por el atacante. El escape se usa para representar caracteres de control como su carácter literal. Si el desarrollador olvida escaparse de un valor obtenido de una select y luego utiliza este valor en otra consulta, entonces bam el atacante tendrá una comilla simple literal de caracteres a su disposición.

Pruebe todo, no confíe en nada.


La inyección SQL puede ocurrir a través de Unicode. Si la aplicación web tiene una URL como esta:

http://mywebapp/widgets/?Code=ABC

que genera SQL como select * desde widgets donde Código = ''ABC''

pero un hacker entra a esto:

http://mywebapp/widgets/?Code=ABC%CA%BC;drop widgets de la tabla desplegable--

el SQL se verá como select * from widgets donde Code = ''ABC''; drop table widgets-- ''

y SQL Server ejecutará dos declaraciones SQL. Uno para hacer la selección y uno para hacer la caída. Es probable que su código convierta el% CA% BC codificado en url en U02BC unicode, que es un "apóstrofo de la letra modificadora". La función Reemplazar en .NET NO tratará eso como una sola cotización. Sin embargo, Microsoft SQL Server lo trata como una sola cotización. Aquí hay un ejemplo que probablemente permitirá la inyección SQL:

string badValue = ((char)0x02BC).ToString(); badValue = badValue + ";delete from widgets--"; string sql = "SELECT * FROM WIDGETS WHERE ID=" + badValue.Replace("''","''''"); TestTheSQL(sql);


La inyección de SQL ocurre si las entradas suministradas por el usuario se interpretan como comandos. Aquí comando significa cualquier cosa que no se interprete como un tipo de datos reconocido literal.

Ahora, si usa la entrada del usuario solo en literales de datos, específicamente solo en literales de cadena, la entrada del usuario solo se interpretaría como algo diferente a los datos de cadena si fuera capaz de dejar el contexto literal de la cadena. Para cadenas de caracteres o literales de cadenas Unicode, son las comillas simples las que encierran los datos literales, mientras que las comillas simples incrustadas deben representarse con dos comillas simples.

Por lo tanto, para dejar un contexto literal de cadena, uno debería proporcionar una sola comilla simple (sic) ya que dos comillas simples se interpretan como datos literales de cadena y no como el delimitador final literal de cadena.

Por lo tanto, si reemplaza una comilla simple en los datos proporcionados por el usuario por dos comillas simples, será imposible para el usuario abandonar el contexto literal de la cadena.


Probablemente no haya una forma 100% segura si está haciendo una concatenación de cadenas. Lo que puede hacer es tratar de verificar el tipo de datos para cada parámetro y si todos los parámetros pasan tal validación, continúe con la ejecución. Por ejemplo, si su parámetro debe ser de tipo int y está obteniendo algo que no se puede convertir a int, simplemente rechace.

Sin embargo, esto no funciona si acepta los parámetros nvarchar.

Como otros ya lo señalaron. La forma más segura es usar consultas parametrizadas.


El uso de parámetros de consulta es mejor, más fácil y más rápido que las comillas de escape.

En su comentario, veo que reconoció la parametrización, pero merece énfasis. ¿Por qué querrías usar el escape cuando pudieras parametrizar?

En Inyección avanzada de SQL En las aplicaciones de SQL Server , busque la palabra "reemplazar" en el texto y, a partir de ese momento, lea algunos ejemplos en los que los desarrolladores permitieron inadvertidamente ataques de inyección de SQL incluso después de escapar de la entrada del usuario.

Existe un caso límite en el que las comillas de escape con / producen una vulnerabilidad, porque / convierte en la mitad de un carácter válido de varios bytes en algunos conjuntos de caracteres. Pero esto no es aplicable a su caso ya que / no es el personaje que escapa.

Como han señalado otros, también puede agregar contenido dinámico a su SQL para algo que no sea un literal de cadena o un literal de fecha. Los identificadores de tabla o columna están delimitados por " en SQL o [ ] en Microsoft / Sybase. Por supuesto, las palabras clave de SQL no tienen ningún delimitador. Para estos casos, recomiendo incluir en la lista blanca los valores para interpolar.

La conclusión es que escapar es una defensa efectiva, si puedes asegurarte de hacerlo constantemente. Ese es el riesgo: que uno de los equipos de desarrolladores en su aplicación podría omitir un paso y hacer algo de interpolación de cadenas de forma insegura.

Por supuesto, lo mismo puede decirse de otros métodos, como la parametrización. Solo son efectivos si los haces consistentemente. Pero creo que es más fácil usar parámetros con mayor rapidez que encontrar el tipo correcto de escape. Y es más probable que los desarrolladores utilicen un método que sea conveniente y no los desacelere.