¿Cómo una conexión de base de datos hace que mysqli_real_escape_string sea más seguro?

1

Estoy aprendiendo PHP + MySQL y observé que la función mysqli_real_escape_string en PHP requiere un identificador a una conexión MySQL. A partir de algunas investigaciones, descubrí que tiene algo que ver con los caracteres charset y multibyte, pero no lo entiendo completamente. Entonces, mi pregunta es ¿cómo ayuda la conexión a la base de datos para que la función mysqli_real_escape_string sea más segura?

    
pregunta VarunAgw 18.12.2013 - 12:02
fuente

2 respuestas

3

Como nota, antes de decir algo sobre este problema: por favor considere avanzar hacia MySQLi o PDO con consultas parametrizadas. No solo son una orden o magnitud más seguras, sino que son más fáciles de trabajar y son totalmente compatibles. Las antiguas funciones de mysql_ ahora se consideran al final de la vida útil y pronto quedarán en desuso. (lo siento, perdí el pequeño i de tu publicación original ... ¡malditas llamadas de procedimiento!)

MySQL opera en cadenas. Las cadenas son dos cosas: una secuencia de bytes y una secuencia de caracteres. La forma en que estas dos secuencias se asignan entre sí se denomina conjunto de caracteres, que se especifica mediante una codificación.

Por ejemplo, ASCII asigna letras, números, símbolos y caracteres de control a los valores de byte 0 a 127. ASCII extendido luego agrega más caracteres para los valores 128 a 255. Otras codificaciones, como la familia UTF (por ejemplo, UTF- 8) utiliza bytes únicos o múltiples para codificar diferentes caracteres. Por ejemplo, los caracteres UTF-16 pueden codificarse como uno o dos puntos de código de 2 bytes (es decir, cada carácter está codificado como 2 o 4 bytes).

La parte interesante sucede cuando se asume un conjunto de caracteres o codificación, pero los datos subyacentes en realidad se codifican de manera diferente. Por ejemplo, el carácter CJK de Asia oriental para "agua" es, que se define en UTF-16 como U + 6C34. Esto codifica a 34 6C en UTF-16LE. Ahora, si asumimos accidentalmente que los datos que recibimos son ASCII, los descodificaremos como "4l" en lugar del carácter Unicode adecuado.

Ahora, ¿qué pasaría si su aplicación de front-end (en este caso PHP) estuviera configurada para usar ASCII extendido, pero la intercalación de su base de datos se configuró en UTF-8 (por ejemplo, utf8_general_ci), y la máquina de su usuario se configuró para usar Windows CP1251 página de códigos cirílicos? En un mundo ideal, cada sistema reconocería los requisitos de la aplicación de destino y los convertiría adecuadamente. Desafortunadamente este no es un mundo ideal. Los bytes subyacentes que representan los caracteres cirílicos probablemente se confundirán con los caracteres ASCII en su camino hacia la aplicación web de PHP. Entonces, cualquier carácter alto (128-255) puede volver a asignarse a diferentes secuencias de bytes cuando los caracteres ASCII se convierten en UTF-8, o incluso pueden formar caracteres completamente nuevos si se traducen accidentalmente ingenuamente en puntos de código UTF-8. En algunos casos, hay reglas especiales que hacen que ciertos puntos de código secuenciales (por ejemplo, marcas diacríticas) se combinen en caracteres de forma especial.

En resumen: la codificación de caracteres es vudú . Esto es serio "aquí hay dragones" territorio. Si puedes obtener una respuesta sensata de cualquiera que haya escrito antes una biblioteca de cadenas real (normalmente solo garabatean "cthulhu ebcdic fhtagn" en tu cara con un marcador mágico y se alejan misteriosamente), entonces Probablemente te diga algunas cosas realmente repugnantes sobre la abominación que es nuestro lenguaje humano.

¿Por qué esto importa para cosas como mysql_escape_string ? Bueno, digamos que su aplicación PHP está en modo UTF-8, pero su servidor MySQL se está ejecutando en modo ASCII. Su usuario escribe un carácter ∻ ( U + 223B ) y su función de escape dice "bueno, shucks, me parece bien, simplemente preocuparse por las citas y esas cosas ". Su servidor MySQL mira esos bytes subyacentes ... oh, resulta que 22 3B es una codificación de "; en ASCII. Whoops!

Esto empeora cuando recuerdas esos trucos de combinación. Puede hacer cosas como aplicar un signo diacrítico a una puntuación, o abofetear esa puntuación en medio de algún texto en árabe, y podría combinarse en un carácter de "forma combinada" con un punto de código totalmente diferente cuando se vuelva a codificar . Esto es importante cuando se utilizan diferentes formatos de codificación modernos, como UTF-8 y UTF-16 juntos.

La función mysql_real_escape_string intenta salvarnos de este infierno al verificar correctamente la cadena una vez que se ha recodificado en la codificación seleccionada del servidor MySQL de destino. Necesita una referencia a la conexión para recuperar estos metadatos del servidor.

La cosa más misericordiosa del mundo, creo, es la incapacidad de la mente humana para comprender las codificaciones de caracteres. Vivimos en una plácida isla de ignorancia en medio de los mares negros de puntos de código, y no estaba destinado a viajar lejos. Las lenguas, cada una de las cuales se esfuerza en su propia dirección, hasta ahora nos han perjudicado poco; pero algún día la unión de planos disociados de Unicode abrirá tales excentricidades terroríficas del lenguaje, y de nuestra posición aterradora en el mismo, que segregaremos de la revelación o huiremos de la luz a la paz y la seguridad de EBCDIC. >

    
respondido por el Polynomial 18.12.2013 - 12:59
fuente
2

El escape debe ser consciente del juego de caracteres, de lo contrario, la lógica de escape puede ser engañada para que acepte caracteres ilegales. Para demostrar esto, puede usar / abusar de los caracteres de varios bytes en una lógica de escape que no conoce el juego de caracteres.

$user_input = "0xC8 ' EVIL_SQL--";
$variable = mysqli_real_escape_string($user_input);
$SqlQuery = "SELECT something FROM some_table WHERE one_thing = '$variable'";

Teniendo en cuenta que la barra invertida está codificada como 0x5C (un byte), nuestra lógica de escape intentará escapar esa comilla simple antes del EVIL_SQL , así que lo que sucederá es que tendremos un byte 0xC8 seguido de 0x5C , que son dos bytes representados como 0xC85C , que es un carácter válido de múltiples bytes (no tengo idea de qué es).

El 0xC8 y la barra invertida se han fusionado para crear un nuevo personaje de bebé. En otras palabras, la barra invertida se ha ido y ya no puede escapar de nuestro ' . Así que el producto final es "SOME_VALID_CHARACTER ' EVIL_SQL" y la consulta SQL final se convierte en

"SELECT something FROM some_table WHERE one_thing = 'SOME_VALID_CHARACTER ' EVIL_SQL--'"

Si nuestro escape se hiciera consciente de la codificación aceptada en el servidor, se pueden tomar algunas medidas para combatir tales ataques.

Más información: Anuncio de MySQL sobre el problema del multibyte SQL inyección y la solución

    
respondido por el Adi 18.12.2013 - 13:12
fuente

Lea otras preguntas en las etiquetas