Me doy cuenta de que las consultas SQL parametrizadas son la forma óptima de desinfectar la entrada del usuario al crear consultas que contienen entrada del usuario, pero me pregunto qué hay de malo en tomar la entrada del usuario y escapar de las comillas simples y rodear toda la cadena con comillas simples. Aquí está el código:
sSanitizedInput = "'" & Replace(sInput, "'", "''") & "'"
Cualquier comilla simple que ingrese el usuario se reemplaza con comillas simples dobles, lo que elimina la capacidad de los usuarios para finalizar la cadena, por lo que cualquier otra cosa que puedan escribir, como punto y coma, signos de porcentaje, etc., formará parte de la cadena y en realidad no se ejecuta como parte del comando.
Estamos utilizando Microsoft SQL Server 2000, por lo que creo que la comilla simple es el único delimitador de cadena y la única forma de escapar del delimitador de cadena, por lo que no hay forma de ejecutar nada que el usuario escriba.
No veo ninguna manera de lanzar un ataque de inyección SQL contra esto, pero me doy cuenta de que si esto fuera tan a prueba de balas como me parece, alguien más lo habría pensado y sería una práctica común.
¿Qué hay de malo con este código? ¿Hay alguna manera de obtener un ataque de inyección SQL más allá de esta técnica de desinfección? Sería muy útil la entrada de muestra del usuario que explota esta técnica.
ACTUALIZAR:
Todavía no conozco ninguna forma de lanzar efectivamente un ataque de inyección SQL contra este código. Algunas personas sugirieron que una barra invertida escaparía a una comilla simple y dejaría que la otra terminara la cadena para que el resto de la cadena se ejecute como parte del comando SQL, y me doy cuenta de que este método funcionaría para inyectar SQL en una base de datos MySQL, pero en SQL Server 2000 la única forma (que he podido encontrar) de escapar de una comilla simple es con otra comilla simple; las barras invertidas no lo harán.
Y a menos que haya una manera de detener el escape de la comilla simple, ninguna de las entradas del resto del usuario se ejecutará porque se tomará como una cadena contigua.
Entiendo que hay mejores formas de desinfectar la información, pero estoy realmente más interesado en saber por qué el método que proporcioné anteriormente no funcionará. Si alguien sabe de alguna forma específica de montar un ataque de inyección SQL contra este método de desinfección, me encantaría verlo.
Respuestas:
En primer lugar, es solo una mala práctica. La validación de entrada siempre es necesaria, pero también siempre es dudosa.
Peor aún, la validación de la lista negra siempre es problemática, es mucho mejor definir explícita y estrictamente qué valores / formatos acepta. Es cierto que esto no siempre es posible, pero en cierta medida siempre debe hacerse.
Algunos trabajos de investigación sobre el tema:
El punto es que cualquier lista negra que haga (y las listas blancas demasiado permisivas) se puede omitir. El último enlace a mi artículo muestra situaciones en las que incluso se puede omitir el escape de citas.
Incluso si estas situaciones no se aplican a usted, sigue siendo una mala idea. Además, a menos que su aplicación sea trivialmente pequeña, tendrá que lidiar con el mantenimiento y tal vez una cierta cantidad de gobierno: ¿cómo se asegura de que se haga bien, en todas partes todo el tiempo?
La forma correcta de hacerlo:
fuente
sp_executesql
lugar deEXEC
). Es decir, puede generar dinámicamente su declaración SQL siempre que ninguno de los textos concatenados provenga del usuario. Esto también tiene beneficios de rendimiento;sp_executesql
admite almacenamiento en caché.De acuerdo, esta respuesta se relacionará con la actualización de la pregunta:
Ahora, además del escape de la barra diagonal inversa de MySQL, y teniendo en cuenta que en realidad estamos hablando de MSSQL, en realidad hay 3 formas posibles de inyectar su código SQL
Tenga en cuenta que estos no serán todos válidos en todo momento y dependen mucho de su código real:
Entonces, lo que obtienes es el nombre de usuario, escapado y luego recortado a 20 caracteres. El problema aquí: pegaré mi cita en el vigésimo carácter (p. Ej., Después de 19 a), y su cita de escape se recortará (en el carácter 21). Entonces el SQL
combinado con el nombre de usuario con formato incorrecto mencionado anteriormente, la contraseña ya estará fuera de las comillas y solo contendrá la carga directamente.
3. Contrabando Unicode: en ciertas situaciones, es posible pasar un personaje Unicode de alto nivel que parece una cita, pero no lo es , hasta que llega a la base de datos, donde de repente está . Dado que no es una cita cuando la valida, será fácil ... Vea mi respuesta anterior para obtener más detalles y enlace a la investigación original.
fuente
En pocas palabras: nunca se escape la consulta. Estás obligado a equivocarte. En su lugar, use consultas parametrizadas, o si no puede hacerlo por alguna razón, use una biblioteca existente que lo haga por usted. No hay razón para hacerlo tú mismo.
fuente
Me doy cuenta de que esto es mucho tiempo después de que se hizo la pregunta, pero ...
Una forma de lanzar un ataque contra el procedimiento 'citar el argumento' es con el truncamiento de cadenas. Según MSDN, en SQL Server 2000 SP4 (y SQL Server 2005 SP1), una cadena demasiado larga se truncará silenciosamente.
Cuando cita una cadena, la cadena aumenta de tamaño. Cada apóstrofe se repite. Esto se puede usar para empujar partes del SQL fuera del búfer. Por lo tanto, podría recortar eficazmente partes de una cláusula where.
Esto probablemente sería principalmente útil en un escenario de página de 'administrador de usuarios' en el que podría abusar de la declaración de 'actualización' para no hacer todas las verificaciones que se suponía que debía hacer.
Por lo tanto, si decide citar todos los argumentos, asegúrese de saber qué sucede con los tamaños de cadena y asegúrese de que no se encuentre con el truncamiento.
Yo recomendaría ir con los parámetros. Siempre. Solo desearía poder aplicar eso en la base de datos. Y como efecto secundario, es más probable que obtenga mejores resultados de caché porque más de las declaraciones se ven iguales. (Esto fue ciertamente cierto en Oracle 8)
fuente
Utilicé esta técnica cuando trabajé con la funcionalidad de 'búsqueda avanzada', donde construir una consulta desde cero era la única respuesta viable. (Ejemplo: permitir que el usuario busque productos basados en un conjunto ilimitado de restricciones en los atributos del producto, mostrando columnas y sus valores permitidos como controles GUI para reducir el umbral de aprendizaje para los usuarios).
En sí mismo es seguro AFAIK. Sin embargo, como señaló otro respondedor, es posible que también deba lidiar con el escape de retroceso (aunque no al pasar la consulta a SQL Server utilizando ADO o ADO.NET, al menos, no puede responder por todas las bases de datos o tecnologías).
El inconveniente es que realmente debe estar seguro de qué cadenas contienen la entrada del usuario (siempre potencialmente maliciosa) y qué cadenas son consultas SQL válidas. Una de las trampas es si usa valores de la base de datos: ¿fueron originalmente proporcionados por el usuario? Si es así, también deben escapar. Mi respuesta es tratar de desinfectar lo más tarde posible (¡pero no más tarde!), Al construir la consulta SQL.
Sin embargo, en la mayoría de los casos, el enlace de parámetros es el camino a seguir: es simplemente más simple.
fuente
El saneamiento de entrada no es algo que quieras burlar. Usa todo tu trasero. Use expresiones regulares en los campos de texto. Pruebe a aplicar sus números al tipo numérico adecuado e informe un error de validación si no funciona. Es muy fácil buscar patrones de ataque en su entrada, como '-. Suponga que todas las entradas del usuario son hostiles.
fuente
flavors
en esa página).Es una mala idea de todos modos, como parece saber.
¿Qué pasa con algo como escapar de la cita en una cadena como esta: \ '
Su reemplazo resultaría en: \ ''
Si la barra diagonal inversa escapa a la primera cita, entonces la segunda cita ha finalizado la cadena.
fuente
Respuesta simple: funcionará a veces, pero no todo el tiempo. Desea usar la validación de la lista blanca en todo lo que hace, pero me doy cuenta de que eso no siempre es posible, por lo que se ve obligado a elegir la mejor lista negra. Del mismo modo, desea utilizar procesos almacenados parametrizados en todo , pero una vez más, eso no siempre es posible, por lo que se ve obligado a usar sp_execute con parámetros.
Hay formas de evitar cualquier lista negra utilizable que se te ocurra (y algunas listas blancas también).
Un informe decente está aquí: http://www.owasp.org/index.php/Top_10_2007-A2
Si necesita hacer esto como una solución rápida para darle tiempo para obtener uno real, hágalo. Pero no pienses que estás a salvo.
fuente
Hay dos formas de hacerlo, sin excepciones, para estar a salvo de las inyecciones de SQL; declaraciones preparadas o procedimientos almacenados prameterizados.
fuente
Si tiene consultas parametrizadas disponibles, debería usarlas en todo momento. Todo lo que se necesita es que una consulta se deslice por la red y su base de datos está en riesgo.
fuente
Sí, eso debería funcionar hasta que alguien ejecute SET QUOTED_IDENTIFIER OFF y use una cita doble para usted.
Editar: no es tan simple como no permitir que el usuario malintencionado apague los identificadores citados:
Hay muchas formas en que QUOTED_IDENTIFIER podría estar desactivado sin que usted lo sepa necesariamente. Es cierto que este no es el exploit de la pistola humeante que estás buscando, pero es una superficie de ataque bastante grande. Por supuesto, si también escapaste de las comillas dobles, entonces volvemos a donde comenzamos. ;)
fuente
Su defensa fallaría si:
(en el último caso, tendría que ser algo que se expandió solo después de haber reemplazado)
fuente
Patrick, ¿estás agregando comillas simples alrededor de TODAS las entradas, incluso las entradas numéricas? Si tiene entrada numérica, pero no pone las comillas simples alrededor, entonces tiene una exposición.
fuente
¡Qué código tan feo sería toda esa desinfección de la entrada del usuario! Luego, el torpe StringBuilder para la declaración SQL. El método de declaración preparado da como resultado un código mucho más limpio, y los beneficios de inyección SQL son una adición realmente agradable.
Además, ¿por qué reinventar la rueda?
fuente
En lugar de cambiar una cita simple a (lo que parece) dos citas simples, ¿por qué no simplemente cambiarla a un apóstrofe, una cita o eliminarla por completo?
De cualquier manera, es un poco un error ... especialmente cuando legítimamente tienes cosas (como nombres) que pueden usar comillas simples ...
NOTA: Su método también supone que todos los que trabajan en su aplicación siempre recuerdan desinfectar la entrada antes de que llegue a la base de datos, lo que probablemente no sea realista la mayor parte del tiempo.
fuente
Si bien puede encontrar una solución que funcione para las cadenas, para los predicados numéricos también debe asegurarse de que solo pasen números (la comprobación simple es ¿se puede analizar como int / double / decimal?).
Es mucho trabajo extra.
fuente
Puede funcionar, pero me parece un poco tonto. Recomiendo verificar que cada cadena sea válida probándola contra una expresión regular.
fuente
Sí, puedes, si ...
Después de estudiar el tema, creo que la información desinfectada como sugirió es segura, pero solo bajo estas reglas:
nunca permite que los valores de cadena que provienen de los usuarios se conviertan en algo más que literales de cadena (es decir, evite dar la opción de configuración: "Ingrese nombres / expresiones de columna SQL adicionales aquí:"). Tipos de valor que no sean cadenas (números, fechas, ...): conviértalos a sus tipos de datos nativos y proporcione una rutina para el literal SQL de cada tipo de datos.
puede usar
nvarchar
/nchar
columnas (y prefijos literales de cadena conN
) O limitar los valores que van avarchar
/char
columnas a caracteres ASCII solamente (por ejemplo, lanzar una excepción al crear una declaración SQL)siempre valida la longitud del valor para que se ajuste a la longitud real de la columna (lanzar excepción si es más larga)
te aseguras de que
SET QUOTED_IDENTIFIER
siempre seaON
Cumpliendo con estos 4 puntos, debe estar seguro. Si viola alguno de ellos, se abre una forma de inyección SQL.
fuente