Inyección de SQL: ¿por qué ya no son seguras las citas de escape?

77

SQL sin formato

Cuando estás escribiendo SQL, para cualquier cosa que realmente requiera aportaciones humanas, se han hecho muchas cosas para evitar la inyección.

Todos los que han oído hablar de la inyección SQL saben que (voy a usar PHP como ejemplo) hacer algo como esto no es seguro:

$sql = "SELECT * FROM 'users' 
.  WHERE 'userName' = "{$_POST["username"]}" 
.  AND 'pass' = "{$_POST["pass"]}";";

Magia

Luego, por supuesto, alguien tuvo la idea de usar "citas de escape mágico" para lidiar con la información del programa que no se había saneado correctamente y se colocó directamente en SQL como resultado de las malas prácticas. Esto realmente no resolvió el problema con la inyección de SQL, pero sí significó que se modificaron todas las entradas de los usuarios.

Añadiendo barras diagonales

Por lo tanto, algunas personas desactivaron las citas mágicas. Luego, analizaron las entradas del usuario antes del punto de SQL a través de addslashes() que, en teoría, escapa a todas las comillas y su pirata informático no puede hacer ' OR 1=1 , pero incluso la documentación para addlashes dice que no debe usar addlashes, dice que usa la función específica de la base de datos como mysql_real_escape_string() , pero algunos todavía dicen que esto no es suficiente.

Agregar barras específicas a la base de datos

Por lo tanto, no podemos usar *_real_escape_string específico de DBMS, no podemos usar add slashes , la cosa de "citas mágicas" causó muchos problemas, y la web está llena de citas con palabras cortas como:

  

"Un hacker dedicado encontrará una manera de   saltar a través de sus bucles de cotización de escape,   simplemente use las declaraciones preparadas de DBAL "- John Q cualquier programador

Bueno, eso me asustó lo suficiente como para usar las declaraciones de preparación y un DBAL. Realmente no explicó nada, pero suena bien porque lo he escuchado mucho.

Declaraciones preparadas

Así que ahora estamos usando PDO, o un DBAL de un marco, o alguna otra cosa que envuelva todos nuestros sql y se asegure de que alguien no pueda ejecutar una inyección de sql.

Mi pregunta es básicamente un "¿por qué no?", no un "¿qué debo usar?". La web está llena de personas que le dicen que use esto o que use eso o lo que sea , pero no hay explicaciones de por qué tuvieron que suceder estas cosas.

Preguntas directas

Preguntas puntuales (recordatorio, estoy preguntando sobre SQL, PHP fue un lenguaje de ejemplo debido a su mala reputación con respecto a SQL, los conceptos son universales):

  1. ¿Por qué no podemos escapar de todas las entradas del usuario usando "magia"?
  2. ¿Por qué las barras no eran "suficientemente buenas"?
  3. ¿Qué tiene de malo usar las funciones de escape específicas de la base de datos, y por qué fue mejor que las barras agregadas?
  4. ¿Por qué las declaraciones preparadas con marcos y PDO se consideran como el estándar de oro de SQL? ¿Por qué son mejores? ¿Por qué no puedo hacer una inyección de SQL con estos, donde, como PODRÍA HACER con los medios mencionados anteriormente? ¿Puede un programador que no de alguna manera logre arruinar esto? ¿Qué deben tener en cuenta?
  5. ¿Alguna otra preocupación que no haya mencionado?
pregunta Incognito 06.05.2011 - 16:44
fuente

7 respuestas

52
  

¿Por qué no podemos escapar de todas las entradas del usuario usando "magia"?

En el momento en que se aplica la magia, se desconoce dónde terminarán los datos. Así que las citas mágicas están destruyendo datos que, a menos que se escriban sin escaparse a una base de datos.

Solo se puede usar en la respuesta HTML enviada al cliente. Piense en un formulario que no se haya rellenado completamente y, por lo tanto, se muestre nuevamente al usuario. Con las comillas mágicas, los datos ingresados en el primer intento ahora serán escapados de SQL, lo cual no tiene sentido en una página HTML. Peor aún: en el segundo envío, los datos son SQL escapados nuevamente.

  

¿Por qué las barras no eran "suficientemente buenas"?

Tiene problemas con los caracteres multibyte:

' 27
\ 5c
뼧 bf 5c

Esos son dos bytes, pero solo un carácter Unicode.

Como addslashes no sabe nada acerca de Unicode, convierte la entrada bf 27 a bf 5c 27 . Si esto es leído por un programa compatible con Unicode, se ve como 뼧 '. Boom.

Hay una buena explicación de este problema en enlace

  

¿Qué tiene de malo usar las funciones de escape específicas de la base de datos, y por qué fue mejor que las barras agregadas?

Son mejores porque se aseguran de que el escape interpreta los datos de la misma forma que lo hace la base de datos (consulte la última pregunta).

Desde un punto de vista de seguridad, están bien si los usa para cada entrada de base de datos. Pero tienen el riesgo de que puedas olvidar a cualquiera de ellos en algún lugar.

Editar : como getahobby agregó: O que use xxx_escape_strings para los números sin agregar comillas alrededor de ellos en la declaración SQL y sin asegurarse de que sean números reales mediante la conversión o conversión de la entrada a la apropiada tipo de datos /Edit

Desde una perspectiva de desarrollo de software, son malos porque hacen que sea mucho más difícil agregar soporte para otro software de servidor de base de datos SQL.

  

¿Por qué las declaraciones preparadas con marcos y PDO se consideran como el estándar de oro de SQL? ¿Por qué son mejores?

La DOP es mayormente buena por razones de diseño de software. Es mucho más fácil admitir otro software de servidor de base de datos. Tiene una interfaz orientada a objetos que abstrae muchas de las pequeñas incompatibilidades específicas de la base de datos.

  

¿Por qué no puedo hacer una inyección de SQL con estas [declaraciones preparadas], donde, como PODRÍA tener, con los medios mencionados anteriormente?

La parte " consulta constante con parámetros variables " de las declaraciones preparadas es lo que es importante aquí. El controlador de la base de datos escapará a todos los parámetros automáticamente sin que el desarrollador tenga que pensar en ello.

Las consultas parametrizadas suelen ser más fáciles de leer que las consultas normales con parámetros escapados por razones sintácticas. Dependiendo del entorno, pueden ser un poco más rápidos.

El uso de declaraciones preparadas con parámetros es algo que puede ser validado por herramientas de análisis de código estático . Una llamada perdida a xxx_escape_string no se detecta de forma fácil y confiable.

  

¿Puede un programador, de alguna manera, no logran arruinar esto todavía? ¿Qué deben tener en cuenta?

Las "declaraciones preparadas" implican que son constantes . La generación dinámica de declaraciones preparadas, especialmente con las aportaciones de los usuarios, aún tiene todos los problemas de inyección.

    
respondido por el Hendrik Brummermann 07.05.2011 - 01:16
fuente
13
  

[1.] ¿Por qué no podemos escapar de todas las entradas del usuario usando "magia"?

Debido a que las citas mágicas se dividen en dos puntos:

  1. No todos los datos de $ _ (REQUEST / GET / POST) van a la base de datos. Y para que puedas entenderlo, debes eliminar la entrada.
  2. Son el equivalente de addslashes (vea mi nota en [2.]), por lo tanto, no son realmente seguros.
  

[2.] ¿Por qué las barras no son "suficientemente buenas"?

Hay muchas maneras de salir de la restricción addslashes , por lo tanto, es fundamentalmente defectuosa, sin embargo, usted intenta usarla.

  

[3.] ¿Qué tiene de malo usar las funciones de escape específicas de la base de datos, y por qué fue mejor que las barras agregadas?

Nada realmente. Ese es simplemente el mantra de por qué la DOP / preparada es "mejor". Son de manera mejores que addslashes ya que se ocupan de muchos factores, incluida la codificación. Aquí hay un pequeño secreto; DOP los usa internamente, pero no addslashes ...

  

[4.] ¿Por qué las declaraciones preparadas con marcos y PDO se consideran el estándar de oro de SQL? ¿Por qué son mejores? ¿Por qué no puedo hacer una inyección de SQL con estos, donde, como PODÍA TENER con los medios mencionados anteriormente?

No son el estándar de oro , no son "más" seguros que las funciones específicas de DB y usted puede hacer una inyección de SQL Con estos también. Y no, no se puede hacer una inyección SQL con una entrada debidamente desinfectada.

Al igual que con todas las tecnologías, los desarrolladores tienden a desarrollar tendencias religiosas (¿fanáticas?) para cualquier cosa "nueva". Es por eso que obtiene la experiencia de Zend Certified Engineers (TM) que le aconseja -no- forzarlo a cambiar a declaraciones preparadas.

La realidad, sin embargo, es que todo depende de saber lo que estás haciendo. Si está cargando un artículo por su ID numérico, no necesita ningún tipo de escape, incluso menos DOP. Simplemente debe asegurarse de que la ID sea un entero.

Desde una perspectiva más realista, la regla general es no usar PDO / declaraciones preparadas, sino usar las funciones correctas, es decir, debe usar mysql_real_escape_string() en lugar de addslashes() o mysql_escape_string() .

  

[5.] ¿Puede un programador, de alguna manera, no lograrlo aún más? ¿Qué deben tener en cuenta?

¡Por supuesto! Pero no se trata de "qué buscar", sino de "saber lo que estás haciendo".

Verá, eval($_GET['code']) * es completamente legítimo cuando se usa en el lugar correcto (como un corredor de pruebas PHP local).

Si usa un ORM para ejecutar una consulta condicional, está ingresando el código directamente, por lo tanto, es posible que reciba una inyección de SQL si no lo hace correctamente (depende del ORM en cuestión). Ejemplo (hipotético):

// update() sets the value of a column given a condition
//
//                         .--escaping is automatic here
//                         |                           .--hypothetical SQL injection
//                         v                           v
Db()->update('name',$_GET['newname'])->where(' id = '.$_GET['id']);

(* Solo puedo imaginar a los innumerables profesionales golpeando su cabeza sobre esto)

    
respondido por el Christian 08.05.2011 - 09:45
fuente
9

Al final del día, se debe realizar el escape de la entrada para proteger sus consultas desde la inyección SQL. Las bibliotecas de consultas parametrizadas como PDO y ADODB utilizan el escape , todo lo que hacen es aplicar esta práctica de una manera que es implícitamente segura. Por contracción, magic_quotes_gpc NOT , este es un enfoque fundamentalmente defectuoso del problema.

1) Escapar puede ser problemático si no entiendes lo que estás haciendo. Este tipo de problema aún es explotable si magic_quotes_gpc está habilitado.

mysql_query("select * from users where id=".addslashes($_GET[id]));

Explotación de PoC: enlace )

patch:

mysql_query("select * from users where id='".addslashes($_GET[id])."'");

Lección: No necesita comillas para explotar la inyección de SQL.

2) Supongamos que solo escapas las comillas:

mysql_query("select * from users where name='".htmlspecialchars($_GET[name],ENT_QUOTES)."' and id='".htmlspecialchars($_GET[id],ENT_QUOTES)."'");

Explotación de PoC: enlace \ & id = + o + sleep (30) / *

Patch:

mysql_query("select * from users where name='".addslashes($_GET[name])."' and id='".addslashes($_GET[id])."'");

Lección : las barras invertidas son igualmente peligrosas como comillas.

3) ¿Qué pasa con la codificación de idioma?

mysql_query("SET CHARACTER SET 'gbk'");
mysql_query("select * from user where name='".addslashes($_GET[name])."'");

Explotación de PoC: http: //localhost/vuln.php? name =% bf% 27 = sleep (30) / *

Patch:

mysql_query("SET CHARACTER SET 'gbk'");
mysql_query("select * from user where name='".mysql_real_escape_string($_GET[name])."'");

Conclusion:

El escape es absolutamente necesario para evitar la inyección de SQL en una aplicación. En PHP, PDO y ADOB son excelentes bibliotecas de consultas parametrizadas que imponen el escape de la entrada del usuario. El problema es que muchos programadores no entienden lo que es escapar. Tener una biblioteca para hacer cumplir esta política de seguridad es el mejor método de defensa, ya que no es necesario comprender las reglas de escape.

    
respondido por el rook 07.05.2011 - 22:25
fuente
5

Acerca de las funciones de escape específicas de la base de datos. Hay muchos escenarios en los que se puede producir la inyección de SQL, aunque se haya utilizado mysql_real_escape_string (). ¡LÍMITE y ORDENAR son realmente difíciles!

Esos ejemplos son vulnerables a la inyección de SQL:

$offset = isset($_GET['o']) ? $_GET['o'] : 0;
$offset = mysql_real_escape_string($offset);
$sql = "SELECT userid, username FROM sql_injection_test LIMIT $offset, 10";

o

$order = isset($_GET['o']) ? $_GET['o'] : 'userid';
$order = mysql_real_escape_string($order);
$sql = "SELECT userid, username FROM sql_injection_test ORDER BY '$order'";

En ambos casos, no puede usar 'para proteger la encapsulación.

fuente : la Inyección de SQL inesperada (cuando el escape no es suficiente) < - Lea esto

    
respondido por el Cut Copy 17.08.2011 - 23:15
fuente
4

Los filtros se pueden omitir y los datos que entran en las sentencias de SQL pueden provenir de más lugares que solo la entrada del usuario. Los puntos de entrada en una fuente / sumidero influenciado por SQL se pueden almacenar (orden superior), como un ejemplo, pero claramente los parámetros HTTP GET y los parámetros POST de los formularios HTML no son las únicas formas de entrada del usuario.

Las consultas parametrizadas no necesariamente hacen que sus declaraciones SQL estén libres de inyecciones. También requieren vinculación variable, eliminación de operaciones / concatenación de cadenas y evitar ciertos problemas de seguridad con una amplia gama de cláusulas SQL.

La mayoría de los desarrolladores también se olvidan de revisar sus componentes de terceros y otras dependencias para problemas de inyección de SQL, y a veces no se dan cuenta de que estas inclusiones podrían hacer que su propio código sea vulnerable.

Lo mejor que puede hacer es contratar una empresa consultora de seguridad de aplicaciones para preparar sus aplicaciones para la preparación de producción, y capacitar a su equipo (s) de appdev para incorporar controles de seguridad de aplicaciones en sus procesos y tecnología de desarrollo. p>     

respondido por el atdre 06.05.2011 - 18:57
fuente
3

Para ampliar la respuesta de Hendrick. Es fácil pensar en real_escape_string como una bala mágica cuando en realidad no lo es. He visto a personas usar esa función cuando quieren usar intval o convertir la entrada a un entero. Aún puede inyectarse si usa la cadena de escape en el contexto incorrecto.

    
respondido por el getahobby 07.05.2011 - 02:00
fuente
-3

Dado que el objetivo es ayudarlo a aprender cómo escribir código decente y no solo copiar una receta, le dejaré algunas sugerencias.

  • Si dejamos cosas de codificación, hay muchas formas de inyectar sql y no todas requieren que agregues "o" o ", por lo tanto, Addslashes es básicamente una solución poco convincente utilizada por desarrolladores cojos y no calificados ... (De los que no deberías leer el código).

  • Esto no sucede mucho, pero en realidad hay un vector donde el atacante puede explotar una declaración preparada, en algunos motores de bases de datos. No es común, pero puede recordar que la declaración preparada usa una declaración pero con el tipo de columna de metatatos de tabla, tamaño ...

  • Otro error cojo habitual es manejar búsquedas en consultas con Me gusta ... Si descubres cómo funciona, puedes hacer algunas cosas interesantes ...

Haga su investigación, nunca confíe en una entrada, nunca use otra cosa que no sea una declaración preparada, ignore a cualquiera que le diga que use escape fu ...

Y debes estar a salvo, recuerda que no tiene sentido obtener nada más de lo que esperas, por lo que tu amigo es un api tan fuerte y tipificado;).

    
respondido por el xlinex 09.10.2014 - 00:48
fuente

Lea otras preguntas en las etiquetas