¿Es seguro no parametrizar una consulta SQL cuando el parámetro no es una cadena?

113

En términos de inyección SQL , entiendo completamente la necesidad de parametrizar un stringparámetro; ese es uno de los trucos más antiguos del libro. Pero, ¿cuándo se puede justificar no parametrizar un SqlCommand? ¿Algún tipo de datos se considera "seguro" para no parametrizar?

Por ejemplo: Yo no me considero en cualquier lugar cerca de un experto en SQL, pero no puedo pensar en ningún casos en los que sería potencialmente vulnerable a la inyección SQL para aceptar una boolo un inty simplemente concatenar la derecha por la consulta.

¿Es correcta mi suposición o eso podría dejar una gran vulnerabilidad de seguridad en mi programa?

Para aclarar, esta pregunta está etiquetada que es un lenguaje fuertemente tipado; cuando digo "parámetro", pienso en algo como public int Query(int id) .

JohnnyRose
fuente
14
No obtendrá el beneficio de los planes de consulta almacenados en caché si no usa parámetros, necesitaría hacer un plan de consulta separado para cada nueva combinación de entradas que proporcione.
Scott Chamberlain
5
@MatthewWhited ¿Cómo sabría que lleva menos tiempo? Esta situación ocurre por todas partes en ciertos proyectos de un desarrollador actual y un desarrollador anterior. Si realmente mejora la seguridad, publique una respuesta. Para aclarar, estoy de acuerdo en que es mejor parametrizar, obviamente. Pero esa no es realmente mi pregunta.
johnnyRose
7
Las consultas parametrizadas se utilizan principalmente para el rendimiento y la optimización. La prevención de la inyección de SQL es un efecto secundario.
Salman A
13
Creo que el OP ha hecho una pregunta válida. Está tratando de evaluar el costo / beneficio de corregir un riesgo potencial. esa ecuación cambia con el potencial de ese riesgo. si hay riesgo cero, yo tampoco lo haría. Se le pidió una pregunta técnica sobre el potencial, no un juicio subjetivo sobre si cree que vale la pena su tiempo. El OP es el único que puede hacer esa llamada.
Sir maldice mucho
10
Para explicarme: soy un dba. Aprecio y respeto las mejores prácticas, y en un mundo perfecto todo el código sería perfecto. Lamentablemente, en el mundo en el que trabajo, tengo más problemas que resolver que tiempo para resolverlos. Eso significa priorización. OMI Reescribir el código que ya funciona, es seguro y funciona a niveles aceptables suena como un lujo. (Que no puedo pagar)
Sir Swears-a-lot

Respuestas:

101

Creo que es seguro ... técnicamente , pero es un hábito terrible. ¿Realmente quieres escribir consultas como esta?

var sqlCommand = new SqlCommand("SELECT * FROM People WHERE IsAlive = " + isAlive + 
" AND FirstName = @firstName");

sqlCommand.Parameters.AddWithValue("firstName", "Rob");

También lo deja vulnerable en la situación en la que un tipo cambia de un número entero a una cadena (piense en el número de empleado que, a pesar de su nombre, puede contener letras).

Por lo tanto, cambiamos el tipo de EmployeeNumber de inta string, pero olvidamos actualizar nuestras consultas SQL. ¡Ups!

Rob
fuente
24
¿Podemos dejar de usar AddWithValue ya? blogs.msmvps.com/jcoehoorn/blog/2014/05/12/…
ComentarioLima
5
@RemarkLima ¿Cuál es la solución cuando genera código dinámicamente que asigna valores a parámetros? La publicación del blog no aborda ese escenario. Sí, es una sola línea para establecer el tipo de SQL cuando se conoce , pero cuando no lo es, entonces tienes un problema (o tienes que recurrir a anotar modelos con esa información).
casperOne
1
Entonces está atascado a AddWithValuemenos que tenga un mapeo de tipos de bases de datos como parte de la construcción dinámica de la declaración. Supongo que tiene una lista de columnas de destino y, como parte del diccionario, podría tener los tipos si lo desea. De lo contrario, solo recibe el impacto del rendimiento. En última instancia, creo que es solo una buena información.
Observación Lima
8
@RemarkLima El punto es "¿ AddWithValueYa podemos dejar de consumir ?" realmente debería ser "si conoce el tipo, entonces debe abstenerse de usar AddWithValue.
casperOne
2
Oye, no dispares al mensajero, yo no lo escribí ;-) pero el punto permanece, y si está integrado en tus diseños desde el principio, no hay razón por la que no debas saber el tipo. Mejores prácticas y todo ese jazz :-)
ComentarioLima
65

Cuando se utiliza una plataforma inflexible de tipos en un equipo a controlar (como un servidor web), puede evitar la inyección de código para las consultas con solamente bool, DateTimeo intlos valores (y otra numérica). Lo que preocupa son los problemas de rendimiento causados ​​por obligar al servidor SQL a volver a compilar cada consulta y evitando que obtenga buenas estadísticas sobre qué consultas se ejecutan con qué frecuencia (lo que perjudica la administración de la caché).

Pero esa parte de "en una computadora usted controla" es importante, porque de lo contrario un usuario puede cambiar el comportamiento utilizado por el sistema para generar cadenas a partir de esos valores para incluir texto arbitrario.

También me gusta pensar a largo plazo. ¿Qué sucede cuando la base de código fuertemente tipada vieja y rota de hoy se transfiere a través de la traducción automática al lenguaje dinámico nuevo y de repente pierde la verificación de tipo, pero aún no tiene todas las pruebas unitarias correctas para el código dinámico? ?

Realmente, no hay una buena razón para no usar parámetros de consulta para estos valores. Es la forma correcta de hacerlo. Continúe y codifique los valores en la cadena sql cuando realmente sean constantes, pero de lo contrario, ¿por qué no usar simplemente un parámetro? No es difícil.

En última instancia, no llamaría a esto un error , per se, pero lo llamaría un olor : algo que no llega a ser un error por sí mismo, pero es una fuerte indicación de que los errores están cerca, o lo estarán eventualmente. Un buen código evita dejar olores, y cualquier buena herramienta de análisis estático lo marcará.

Agregaré que, desafortunadamente, este no es el tipo de argumento que puedes ganar directamente. Suena como una situación en la que estar "en lo correcto" ya no es suficiente, y no es probable que pisar los pies de sus compañeros de trabajo para solucionar este problema por su cuenta promueva una buena dinámica de equipo; en última instancia, podría doler más de lo que ayuda. Un mejor enfoque en este caso puede ser promover el uso de una herramienta de análisis estático. Eso daría legitimidad y credibilidad a los esfuerzos dirigidos y retrocediendo y arreglando el código existente.

Joel Coehoorn
fuente
1
Definitivamente no es un desafío hacerlo parametrizado. Mi pregunta surgió porque un compañero de trabajo escribió un montón de consultas concatenando valores enteros y me preguntaba si era una pérdida de tiempo revisarlas y corregirlas todas.
johnnyRose
2
Creo que la pregunta "¿Es un error" es a lo que se reduce mi pregunta?
johnnyRose
7
Es un "olor": algo que no llega a ser un error por sí solo, pero indica que es probable que haya errores cerca. El buen código intenta eliminar los olores. Cualquier buena herramienta de análisis estático definitivamente lo marcaría.
Joel Coehoorn
1
Me gusta el término "olor". En su lugar, habría usado algo como "larva", donde todavía no es un error, pero las actualizaciones futuras podrían atraparlo a un gusano que se comerá en su backend hasta que lo aplaste o fumigue. Ciertamente, no desea que surja la posibilidad de que surja un código necrótico en un entorno de producción, y tener algo que no se desarrolló con cierta delicadeza ciertamente podría causar que esto esté presente, como en este caso.
CSS
1
Esto está simplemente mal. Vea mi respuesta, por ejemplo, sobre cómo aún puede crear inyección SQL con DateTimeoint
Kaspars Ozols
53

En algunos casos, ES posible realizar un ataque de inyección SQL con variables no parametrizadas (concatenadas) que no sean valores de cadena; consulte este artículo de Jon: http://codeblog.jonskeet.uk/2014/08/08/the-bobbytables -cultura / .

El problema es que cuando ToStringse llama, algún proveedor de cultura personalizada puede transformar un parámetro que no es una cadena en su representación de cadena, lo que inyecta algo de SQL en la consulta.

Maciek
fuente
14
Creo que esta es la única publicación que responde a la pregunta, que esencialmente es "¿Cómo puede ser posible la inyección con ints?"
Arturo Torres Sánchez
3
Sin embargo, si está en condiciones de inyectar código personalizado, como trampa explosiva, es CultureInfodifícil saber por qué necesitaría la inyección SQL de todos modos.
Martin Smith
más 1, la única respuesta que realmente responde a la pregunta
ken2k
@MartinSmith: vea mi respuesta, que muestra una forma posible de cambiar CultureInfo desde afuera.
user1027167
Si una persona puede escribir dicho código en la aplicación, ¿por qué necesita la inyección SQL?
Reza Aghaei
51

Esto no es seguro incluso para tipos que no son cadenas. Utilice siempre parámetros. Período.

Considere el siguiente ejemplo de código:

var utcNow = DateTime.UtcNow;
var sqlCommand = new SqlCommand("SELECT * FROM People WHERE created_on <= '" + utcNow + "'");

A primera vista, el código parece seguro, pero todo cambia si realiza algunos cambios en la configuración regional de Windows y agrega una inyección en formato de fecha corta:

Inyección de fecha y hora

Ahora el texto del comando resultante se ve así:

SELECT * FROM People WHERE created_on <= '26.09.2015' OR '1'<>' 21:21:43'

Se puede hacer lo mismo para el inttipo, ya que el usuario puede definir un signo negativo personalizado que se puede cambiar fácilmente a una inyección SQL.

Se podría argumentar que la cultura invariante debería usarse en lugar de la cultura actual, pero he visto concatenaciones de cadenas como esta tantas veces y es bastante fácil pasar por alto cuando se concatenan cadenas con objetos usando +.

Kaspars Ozols
fuente
10
¿Quién puede cambiar la configuración del servidor? Si una persona puede hacerlo en su servidor, no necesita la inyección SQL para destruir datos.
Reza Aghaei
5
Esta es la mejor respuesta, muestra una forma que valida la preocupación de los OP: esto es un error / falla de seguridad. Dejando de lado el rendimiento y la prueba de futuro, la concatenación de fechas y horas en SQL, por ejemplo, no es solo un olor o una deuda tecnológica . @RezaAghaei, la pregunta nunca mencionó el lado del servidor, podría ser una aplicación de Windows con SQLExpress; de cualquier manera, ese no es un criterio para la pregunta. Cualquiera podría decir quién tiene acceso a la configuración del servidor para refutar esta excelente respuesta, al igual que cualquiera podría decir qué pasa con el alojamiento de servidor compartido o un error del año 2000. Estoy de acuerdo con que el servidor esté bloqueado, simplemente no es un requisito previo.
Jeremy Thompson
2
¿Podría dar un ejemplo de lo que estaba diciendo sobre el inttipo?
johnnyRose
1
Sé que han pasado algunas semanas desde que respondió esto, pero ¿sería posible que editara su publicación y agregara un ejemplo de cómo puede definir un signo negativo personalizado?
johnnyRose
23

"SELECT * FROM Table1 WHERE Id =" + intVariable.ToString ()


Seguridad
Está bien.
Los atacantes no pueden inyectar nada en su variable int escrita.

Rendimiento
incorrecto.

Es mejor usar parámetros, por lo que la consulta se compilará una vez y se almacenará en caché para el próximo uso. La próxima vez, incluso con diferentes valores de parámetros, la consulta se almacena en caché y no necesita compilarse en el servidor de la base de datos.

Estilo de codificación
Mala práctica.

  • Los parámetros son más legibles
  • Tal vez lo haga acostumbrarse a las consultas sin parámetros, luego tal vez cometió un error una vez y usó un valor de cadena de esta manera y entonces probablemente debería despedirse de sus datos. ¡Mal hábito!


"SELECT * FROM Product WHERE Id =" + TextBox1.Text


Aunque no es tu pregunta, pero quizás sea útil para futuros lectores:


¡Desastre de seguridad !
Incluso cuando el Idcampo es un número entero, su consulta puede estar sujeta a inyección SQL. Suponga que tiene una consulta en su aplicación "SELECT * FROM Table1 WHERE Id=" + TextBox1.Text, un atacante puede insertar en el cuadro de texto 1; DELETE Table1y la consulta será:

"SELECT * FROM Table1 WHERE Id=1; DELETE Table1"

Si no desea usar una consulta parametrizada aquí, debe usar valores escritos:

string.Format("SELECT * FROM Table1 WHERE Id={0}", int.Parse(TextBox1.Text))


Tu pregunta


Mi pregunta surgió porque un compañero de trabajo escribió un montón de consultas concatenando valores enteros y me preguntaba si era una pérdida de tiempo revisarlos y solucionarlos todos.

Creo que cambiar esos códigos no es una pérdida de tiempo. De hecho, se recomienda el cambio.

si su compañero de trabajo usa variables int, no tiene ningún riesgo de seguridad, pero creo que cambiar esos códigos no es una pérdida de tiempo y, de hecho, se recomienda cambiar esos códigos. Hace que el código sea más legible, más fácil de mantener y hace que la ejecución sea más rápida.

Reza Aghaei
fuente
Incluso la primera opción no está completamente bien por seguridad. El comportamiento de .ToString()está determinado por un elemento de configuración del sistema operativo que es fácil de cambiar para incluir texto arbitrario.
Joel Coehoorn
18

En realidad, hay dos preguntas en una. Y la pregunta del título tiene muy poco que ver con las preocupaciones expresadas por el OP en los comentarios posteriores.

Aunque me doy cuenta de que para el OP es su caso particular lo que importa, para los lectores que vienen de Google, es importante responder a la pregunta más general, que puede expresarse como "¿Es la concatenación tan segura como las declaraciones preparadas si me asegure que cada literal que estoy concatenando es seguro? ". Entonces, me gustaría concentrarme en este último. Y la respuesta es

Definitivamente no.

La explicación no es tan directa como le gustaría a la mayoría de los lectores, pero haré todo lo posible.

He estado reflexionando sobre el tema durante un tiempo, lo que resultó en el artículo (aunque basado en el entorno PHP) donde traté de resumir todo. Se me ocurrió que la cuestión de la protección contra la inyección de SQL a menudo se elude hacia algunos temas relacionados pero más estrechos, como el escape de cadenas, la conversión de tipos y demás. Aunque algunas de las medidas pueden considerarse seguras cuando se toman por sí mismas, no existe un sistema ni una regla simple a seguir. Lo que hace que sea un terreno muy resbaladizo, poniendo demasiado en la atención y experiencia del desarrollador.

La cuestión de la inyección de SQL no se puede simplificar a una cuestión de sintaxis en particular. Es más amplio de lo que pensaba el desarrollador promedio. También es una cuestión metodológica . No se trata solo de "Qué formato en particular debemos aplicar", sino también de " Cómo se debe hacer".

(Desde este punto de vista, un artículo de Jon Skeet citado en la otra respuesta lo está haciendo bastante mal que bien, ya que nuevamente es quisquilloso en algún caso límite, se concentra en un problema de sintaxis en particular y no aborda el problema en su totalidad).

Cuando intenta abordar la cuestión de la protección no como un todo, sino como un conjunto de diferentes problemas de sintaxis, se enfrenta a una multitud de problemas.

  • la lista de posibles opciones de formato es realmente enorme. Significa que uno puede fácilmente pasar por alto algunos. O confúndalos (por ejemplo, utilizando cadena de escape para el identificador ).
  • La concatenación significa que todas las medidas de protección deben ser realizadas por el programador, no por el programa. Este problema por sí solo tiene varias consecuencias:
    • tal formateo es manual. Manual significa extremadamente propenso a errores. Uno podría simplemente olvidarse de aplicar.
    • además, existe la tentación de trasladar los procedimientos de formateo a alguna función centralizada, estropeando aún más las cosas y estropeando los datos que no van a la base de datos.
  • cuando hay más de un desarrollador involucrado, los problemas se multiplican por diez.
  • cuando se utiliza la concatenación, no se puede decir una consulta potencialmente peligrosa de un vistazo: ¡ todas son potencialmente peligrosas!

A diferencia de ese lío, las declaraciones preparadas son de hecho El Santo Grial:

  • se puede expresar en forma de una regla simple que es fácil de seguir.
  • es una medida esencialmente irrompible, significa que el desarrollador no puede interferir y, voluntaria o involuntariamente, estropear el proceso.
  • la protección contra la inyección es en realidad sólo un efecto secundario de las declaraciones preparadas, cuyo propósito real es producir declaraciones sintácticamente correctas. Y una declaración sintácticamente correcta es 100% a prueba de inyecciones. Sin embargo, necesitamos que nuestra sintaxis sea correcta a pesar de cualquier posibilidad de inyección.
  • si se usa en todos los sentidos, protege la aplicación independientemente de la experiencia del desarrollador. Diga, hay algo que se llama inyección de segundo orden . Y un engaño muy fuerte que dice "para proteger, escapar de todas las entradas proporcionadas por el usuario ". Combinados, conducen a la inyección, si un desarrollador se toma la libertad de decidir qué debe protegerse y qué no.

(Pensando más, descubrí que el conjunto actual de marcadores de posición no es suficiente para las necesidades de la vida real y debe extenderse, tanto para estructuras de datos complejas, como matrices, e incluso palabras clave SQL o identificadores, que a veces deben agregarse al consulta dinámicamente también, pero un desarrollador se queda desarmado para tal caso y se ve obligado a recurrir a la concatenación de cadenas, pero eso es otra cuestión).

Curiosamente, la controversia de esta pregunta es provocada por la naturaleza muy controvertida de Stack Overflow. La idea del sitio es hacer uso de preguntas particulares de los usuarios que preguntan directamente para lograr el objetivo de tener una base de datos de respuestas de propósito general adecuada para los usuarios que provienen de la búsqueda . La idea no es mala per se , pero falla en una situación como esta: cuando un usuario hace una pregunta muy limitada , particularmente para tener una discusión en una disputa con un colega (o para decidir si vale la pena refactorizar el código). Si bien la mayoría de los participantes experimentados están tratando de escribir una respuesta, teniendo en cuenta la misión de Stack Overflow en su totalidad, lo que hace que su respuesta sea buena para tantos lectores como sea posible, no solo para el OP.

Tu sentido común
fuente
10
No responde la pregunta
edc65
La mayoría de las bases de datos detectan consultas ya utilizadas y parametrizadas mediante la igualdad de cadenas SQL, por lo que el antiguo método de preparación y uso me parece obsoleto. Estos mangos se pueden usar solo dentro de un cierto alcance y requieren codificación para realizar un seguimiento del mango. Las consultas parametrizadas deberían, en mi opinión, usarse directamente, de modo que los planes de consulta se puedan reutilizar sin el seguimiento del control e incluso en diferentes aplicaciones.
Erik Hart
15

No pensemos solo en consideraciones de seguridad o de seguridad de tipos.

La razón por la que utiliza consultas parametrizadas es para mejorar el rendimiento a nivel de la base de datos. Desde la perspectiva de una base de datos, una consulta parametrizada es una consulta en el búfer SQL (para usar la terminología de Oracle, aunque imagino que todas las bases de datos tienen un concepto similar internamente). Entonces, la base de datos puede contener una cierta cantidad de consultas en la memoria, preparadas y listas para ejecutarse. Estas consultas no necesitan ser analizadas y serán más rápidas. Las consultas que se ejecutan con frecuencia suelen estar en el búfer y no es necesario analizarlas cada vez que se utilizan.

A NO SER QUE

Alguien no usa consultas parametrizadas. En este caso, el búfer se vacía continuamente a través de un flujo de consultas casi idénticas, cada una de las cuales debe ser analizada y ejecutada por el motor de la base de datos y el rendimiento se ve afectado por completo, ya que incluso las consultas que se ejecutan con frecuencia terminan siendo analizadas varias veces al día. día. Me he ganado la vida sintonizando bases de datos y esta ha sido una de las mayores fuentes de fruta madura.

AHORA

Para responder a su pregunta, SI su consulta tiene una pequeña cantidad de valores numéricos distintos, probablemente no causará problemas y, de hecho, puede mejorar el rendimiento infinitesimalmente. Sin embargo, si hay potencialmente cientos de valores y la consulta recibe muchas llamadas, afectará el rendimiento de su sistema, así que no lo haga.

Sí, puede aumentar el búfer SQL, pero siempre es a expensas de otros usos más críticos de la memoria, como el almacenamiento en caché de índices o datos. Moraleja, use consultas parametrizadas de manera bastante religiosa para que pueda optimizar su base de datos y usar más memoria del servidor para las cosas que importan ...

mcottle
fuente
8

Para agregar algo de información a la respuesta de Maciek:

Es fácil alterar la información cultural de una aplicación de terceros .NET llamando a la función principal del ensamblado por reflexión:

using System;
using System.Globalization;
using System.Reflection;
using System.Threading;

namespace ConsoleApplication2
{
  class Program
  {
    static void Main(string[] args)
    {
      Assembly asm = Assembly.LoadFile(@"C:\BobbysApp.exe");
      MethodInfo mi = asm.GetType("Test").GetMethod("Main");
      mi.Invoke(null, null);
      Console.ReadLine();
    }

    static Program()
    {
      InstallBobbyTablesCulture();
    }

    static void InstallBobbyTablesCulture()
    {
      CultureInfo bobby = (CultureInfo)CultureInfo.InvariantCulture.Clone();
      bobby.DateTimeFormat.ShortDatePattern = @"yyyy-MM-dd'' OR ' '=''";
      bobby.DateTimeFormat.LongTimePattern = "";
      bobby.NumberFormat.NegativeSign = "1 OR 1=1 OR 1=";
      Thread.CurrentThread.CurrentCulture = bobby;
    }
  }
}

Esto solo funciona si la función principal de BobbysApp es pública. Si Main no es público, puede haber otras funciones públicas a las que podría llamar.

usuario1027167
fuente
1
Ni siquiera tienes que hacerlo por código. Puede agregar inyección directamente en la configuración regional de Windows. Mira mi respuesta.
Kaspars Ozols
2
¿Quién puede cambiar la configuración del servidor o quién puede frotar dicho código en el servidor? Si una persona puede hacerlo en su servidor, no necesita la inyección SQL para destruir datos.
Reza Aghaei
7

En mi opinión, si puede garantizar que el parámetro con el que trabaja nunca contendrá una cadena, es seguro, pero no lo haría en ningún caso. Además, verá una ligera caída en el rendimiento debido al hecho de que está realizando una concatenación. La pregunta que te haría es ¿por qué no quieres usar parámetros?

Max
fuente
1
No es que no quiera usar parámetros, estoy usando parámetros. Un compañero de trabajo escribió un código como este que modifiqué para parametrizarlo hoy, lo que me hizo pensar en la pregunta.
johnnyRose
Okay. Excelente. Es una buena práctica utilizar parámetros. De esta manera, no tiene que preocuparse por cosas como la inyección SQL. Además, si está creando consultas dinámicas, también puede usar parámetros sin importar cuán complejas sean sus consultas. Simplemente use el estilo @ 1 ... @ n al crearlos. Y añádalos a la colección de parámetros con el valor deseado.
Max
@johnyRose Hay un punto más para usar los parámetros: los programas están evolucionando y cambiando. Puede usar la concatenación solo para cadenas, pero eso no garantiza que alguien implemente la refactorización que cambie algún tipo de parámetro y que los cambios puedan introducir una vulnerabilidad de inyección SQL.
lerthe61
3

Está bien pero nunca es seguro ... y la seguridad siempre depende de las entradas, por ejemplo, si el objeto de entrada es TextBox, los atacantes pueden hacer algo complicado ya que el cuadro de texto puede aceptar cadenas, por lo que hay que poner algún tipo de validación / conversión para poder evitar que los usuarios ingresen incorrectamente. Pero la cosa es que no es seguro. Tan simple como eso.

japzdivino
fuente
Aunque eso es una cuerda. Estoy hablando de otros tipos de datos, como enteros, booleanos o fechas.
johnnyRose
@johnnyRose Sí, he visto un ejemplo muy bueno arriba que marca como respondido por Kaspards ... y una gran respuesta ya que usa el tipo de datos de fecha y hora como ejemplo, lo cual es poco común. :) Espero que ya esté convencido de que no es seguro y mejor usar el parámetro en cualquier tipo de tipo de datos
japzdivino
Realmente nunca tuve ninguna duda de que era más seguro usar parámetros. Mi pregunta se refería a implementaciones fuertemente tipadas.
johnnyRose
Sí ... estoy de acuerdo. y esa también es una gran pregunta que puede ayudar a los futuros lectores :)
japzdivino
-2

No, puede obtener un ataque de inyección SQL de esa manera. He escrito un artículo antiguo en turco que muestra cómo aquí . Ejemplo de artículo en PHP y MySQL pero el concepto funciona igual en C # y SQL Server.

Básicamente atacas de la siguiente manera. Consideremos que tiene una página que muestra información de acuerdo con el valor de ID de número entero. No ha parametrizado este valor, como se muestra a continuación.

http://localhost/sqlEnjeksiyon//instructors.aspx?id=24

Bien, supongo que estás usando MySQL y ataco de la siguiente manera.

http://localhost/sqlEnjeksiyon//instructors.aspx?id=ASCII((SELECT%20DATABASE()))

Tenga en cuenta que aquí el valor inyectado no es una cadena. Estamos cambiando el valor char a int usando la función ASCII. Puede lograr lo mismo en SQL Server usando "CAST (YourVarcharCol AS INT)".

Después de eso, uso las funciones de longitud y subcadena para encontrar el nombre de su base de datos.

http://localhost/sqlEnjeksiyon//instructors.aspx?id=LEN((SELECT%20DATABASE()))

http://localhost/sqlEnjeksiyon//instructors.aspx?id=ASCII(SUBSTR(SELECT%20DATABASE(),1,1))

Luego, usando el nombre de la base de datos, comienza a obtener nombres de tablas en la base de datos.

http://localhost/sqlEnjeksiyon//instructors.aspx?id=ASCII(SUBSTR((SELECT table_name FROM INFORMATION_SCHEMA.TABLES LIMIT 1),1,1))

Por supuesto que tienes que automatizar este proceso, ya que solo obtienes UN carácter por consulta. Pero puedes automatizarlo fácilmente. Mi artículo muestra un ejemplo en watir . Utilizando solo una página y sin valor de ID parametrizado. Puedo aprender cada nombre de tabla en su base de datos. Después de eso puedo buscar tablas importantes. Llevará tiempo, pero es factible.

Atilla Ozgur
fuente
2
Mi pregunta se refiere a un lenguaje fuertemente tipado. Si bien su explicación es excelente para los idiomas con escritura flexible, el valor inyectado sigue siendo una cadena.
johnnyRose
Ningún valor inyectado es un número entero. Obtiene char y lo cambia a entero usando la función ASCII MySQL. Hace lo mismo en SQL Server usando CAST (YourCharValue AS INT)
Atilla Ozgur
public void QuerySomething(int id) { // this will only accept an integer }
Quise
-3

Bueno ... una cosa es segura: la seguridad NO está bien, cuando concatenas una cadena (tomada por el usuario) con tu cadena de comandos SQL. No importa siempre que la cláusula where se refiera a un Entero oa cualquier tipo; pueden producirse inyecciones.

Lo que importa en SQL Injection es el tipo de datos de la variable que solía obtener el valor del usuario.

Suponiendo que tenemos un número entero en la cláusula where y:

  1. la variable de usuario es una cadena. Entonces está bien, no es muy fácil de inyectar (usando UNION) pero es muy fácil pasar por alto usando 'OR 1 = 1' - como ataques ...

  2. Si la variable de usuario es un número entero. Entonces, nuevamente podemos 'probar' la fuerza del sistema pasando pruebas de números grandes inusuales para detectar fallas del sistema o incluso para un desbordamiento de búfer oculto (en la cadena final) ...;)

Quizás los parámetros de las consultas o (mejor aún, en mi opinión) de los Procedimientos almacenados no son 100% seguros para las amenazas, pero son la medida menos necesaria (o la más elemental si lo prefiere) para minimizarlas.

Andreas Venieris
fuente
Creo que podría haber entendido mal la pregunta. Estoy hablando de tipos que no son de cadena.
johnnyRose
Hola JonnyRose ... gracias por tu nota. Entiendo su pregunta, pero solo expreso mi respuesta en una forma más general. Para el caso sin cuerdas, verifique mi (2) punto. ;)
Andreas Venieris