Alternativa a mysql_real_escape_string sin conectarse a DB

91

Me gustaría tener una función que se comporte como mysql_real_escape_string sin conectarme a la base de datos, ya que a veces necesito hacer pruebas en seco sin conexión a la base de datos. mysql_escape_string está obsoleto y, por lo tanto, no es deseable. Algunos de mis hallazgos:

http://www.gamedev.net/community/forums/topic.asp?topic_id=448909

http://w3schools.invisionzone.com/index.php?showtopic=20064

Viet
fuente
1
+1 Estoy escribiendo la clase MySQL yo mismo y uso mysql_real_escape_string () para el enlace de parámetros. Evito usar mysqli ya que no todos los alojamientos lo admiten. También evito la biblioteca de múltiples archivos y clases. Lo que necesito es una sola clase ordenada y limpia. ¡Gracias!
Viet
+1 para mí también. Mi caso de uso es una API de SugarCRM en la que necesito enviar fragmentos de SQL a la instancia remota de SugarCRM a través de la API. Por desagradable que sea, es con lo que tengo que trabajar (ve a juntar algunas cabezas de desarrollo de SugarCRM). Necesito escapar de las cadenas en SQL en la aplicación que usa la API y que está totalmente separada de la base de datos detrás de la instancia de SugarCRM.
Jason

Respuestas:

75

Es imposible escapar de forma segura de una cadena sin una conexión DB. mysql_real_escape_string()y las declaraciones preparadas necesitan una conexión a la base de datos para que puedan escapar de la cadena usando el juego de caracteres apropiado; de lo contrario, los ataques de inyección SQL aún son posibles usando caracteres de múltiples bytes.

Si solo está probando , entonces también puede usar mysql_escape_string(), no está 100% garantizado contra ataques de inyección de SQL, pero es imposible construir algo más seguro sin una conexión de base de datos.

demasiado php
fuente
1
+1 Gracias por la nota. No estoy muy seguro de cómo realizar pruebas contra ataques de inyección de SQL utilizando caracteres de varios bytes.
Viet
2
Me dieron un código antiguo para actualizar. Se usa mysql_escape_stringsin conexión (todavía estoy tratando de averiguar por qué). Dado que esa función está en desuso, me pregunto cómo puedo reemplazarla. Ciertamente parece razonable que se pueda especificar el "juego de caracteres apropiado" en cualquier función que lo reemplace sin abrir una conexión.
JohnK
3
¿Imposible? ¿Qué obtiene mysql_real_escape_string de la conexión de la base de datos que no son datos de configuración que podrían pasarse manualmente a una función equivalente? Editar: solo lea a continuación, llama a una función de biblioteca dentro de MySQL, por lo que hay algún procesamiento que ocurre fuera de PHP. Puede que aún sea portátil, pero mantenerlo actualizado sería un proyecto en sí mismo.
Jason
2
¿Qué pasa si el juego de caracteres de la base de datos se conoce de antemano?
jchook
7
Sí, si conoces el conjunto de caracteres, ¿qué impide escapar sin una conexión?
Johan
65

Bueno, de acuerdo con la página de referencia de la función mysql_real_escape_string : "mysql_real_escape_string () llama a la función de biblioteca de MySQL mysql_real_escape_string, que escapa a los siguientes caracteres: \ x00, \ n, \ r, \, '," y \ x1a ".

Con eso en mente, entonces la función dada en el segundo enlace que publicó debería hacer exactamente lo que necesita:

function mres($value)
{
    $search = array("\\",  "\x00", "\n",  "\r",  "'",  '"', "\x1a");
    $replace = array("\\\\","\\0","\\n", "\\r", "\'", '\"', "\\Z");

    return str_replace($search, $replace, $value);
}
zombat
fuente
6
Gracias. Sugeriría algo más: function escape ($ aQuery) {return strtr ($ aQuery, array ("\ x00" => '\ x00', "\ n" => '\ n', "\ r" => '\ r', '\\' => '\\\\', "'" => "\'", '"' => '\"', "\ x1a" => '\ x1a')) ; }
Viet
1
¿Por qué \ x1a se reemplaza por \\\ x1a en lugar de \\ x1a? ¿Es esto un error tipográfico?
Michael Z
16
-1 Esto es extremadamente peligroso. Si la conexión a la base de datos utiliza un conjunto de caracteres de varios bytes, los reemplazos simples de bytes como este podrían provocar la corrupción de datos (incluidos caracteres de escape / comillas); esto puede ser explotado deliberadamente por un atacante malintencionado para inyectar SQL arbitrario.
eggyal
Si se equivoca en el juego de caracteres, puede ser peligroso. Para conjuntos de caracteres multibyte, si mysql está usando eso, alguien puede simplemente ingresar un byte para cancelar el \\. Los conjuntos de caracteres de varios bytes a menudo pueden tomar cualquier cosa, ya que el segundo byte, incluido \\, para mysql no lo verá como un \\ independiente, sino como parte del carácter de varios bytes. No tengo idea de lo que sucede con UTF8. Espero que con [0xB0, '\\'] al presionar un byte inválido \\ que simplemente se detenga y comience de nuevo con ese byte en lugar de tragarlo.
jgmjgm
1
Si sé que el juego de caracteres es utf8, ¿es seguro usarlo mb_strpos()(y mb_substr()crear un comportamiento similar a substr_replace()) para hacer esto?
SOFe
28

En oposición directa a mi otra respuesta, esta función siguiente probablemente sea segura, incluso con caracteres de varios bytes.

// replace any non-ascii character with its hex code.
function escape($value) {
    $return = '';
    for($i = 0; $i < strlen($value); ++$i) {
        $char = $value[$i];
        $ord = ord($char);
        if($char !== "'" && $char !== "\"" && $char !== '\\' && $ord >= 32 && $ord <= 126)
            $return .= $char;
        else
            $return .= '\\x' . dechex($ord);
    }
    return $return;
}

Espero que alguien con más conocimientos que yo pueda decirme por qué el código anterior no funciona ...

demasiado php
fuente
+1 Gracias por el esfuerzo extra. Voy a buscar más información sobre las inyecciones SQL relacionadas con varios bytes.
Viet
Supongo que debería ser $ return. = '\ X'. dechex ($ ord); en su lugar
Viet
1
Como regla general, prefiero usar '\\' incluso en cadenas entre comillas simples, solo porque una sola '\' puede afectar al siguiente carácter si no se tiene cuidado. Probablemente estoy volviendo a tener TOC.
demasiado php
1
Esta función no sigue las reglas de escape de mysql y resultará en la pérdida de la integridad de los datos. "MySQL reconoce las secuencias de escape que se muestran en la Tabla 9.1," Secuencias de escape de caracteres especiales ". Para todas las demás secuencias de escape, la barra invertida se ignora. Es decir, el carácter de escape se interpreta como si no se hubiera escapado. Por ejemplo," \ x " es solo "x". " - dev.mysql.com/doc/refman/5.6/en/...
Velcrow
2
¿\ XAA realmente significa algo más que el texto "xAA" en un literal de cadena de MySQL? La documentación parece decir que \ x no tiene ningún significado especial, por lo que \ se ignorará. dev.mysql.com/doc/refman/5.0/en/string-literals.html
Jason
6

De investigaciones posteriores, encontré:

http://dev.mysql.com/doc/refman/5.1/en/news-5-1-11.html

Corrección de seguridad:

Se ha encontrado un agujero de seguridad de inyección SQL en el procesamiento de codificación multibyte. El error estaba en el servidor, el análisis incorrecto de la cadena escapó con la función de API de C mysql_real_escape_string ().

Esta vulnerabilidad fue descubierta e informada por Josh Berkus y Tom Lane como parte de la colaboración de seguridad entre proyectos del consorcio OSDB. Para obtener más información sobre la inyección SQL, consulte el siguiente texto.

Discusión. Se ha encontrado un agujero de seguridad de inyección SQL en el procesamiento de codificación multibyte. Un agujero de seguridad de inyección de SQL puede incluir una situación en la que cuando un usuario proporciona datos para ser insertados en una base de datos, el usuario puede inyectar sentencias de SQL en los datos que ejecutará el servidor. Con respecto a esta vulnerabilidad, cuando se utiliza un escape sin conocimiento del conjunto de caracteres (por ejemplo, añade barras () en PHP), es posible omitir el escape en algunos conjuntos de caracteres de varios bytes (por ejemplo, SJIS, BIG5 y GBK). Como resultado, una función como addedlashes () no puede prevenir ataques de inyección de SQL. Es imposible arreglar esto en el lado del servidor. La mejor solución es que las aplicaciones utilicen el escape con reconocimiento de conjuntos de caracteres que ofrece una función como mysql_real_escape_string ().

Sin embargo, se detectó un error en cómo el servidor MySQL analiza la salida de mysql_real_escape_string (). Como resultado, incluso cuando se usó la función mysql_real_escape_string () consciente del juego de caracteres, la inyección de SQL fue posible. Este error se ha corregido.

Soluciones alternativas. Si no puede actualizar MySQL a una versión que incluye la solución para el error en el análisis de mysql_real_escape_string (), pero ejecuta MySQL 5.0.1 o superior, puede usar el modo SQL NO_BACKSLASH_ESCAPES como solución. (Este modo se introdujo en MySQL 5.0.1.) NO_BACKSLASH_ESCAPES habilita un modo de compatibilidad estándar SQL, donde la barra invertida no se considera un carácter especial. El resultado será que las consultas fallarán.

Para configurar este modo para la conexión actual, ingrese la siguiente instrucción SQL:

SET sql_mode='NO_BACKSLASH_ESCAPES';

También puede configurar el modo globalmente para todos los clientes:

SET GLOBAL sql_mode='NO_BACKSLASH_ESCAPES';

Este modo SQL también se puede habilitar automáticamente cuando el servidor se inicia usando la opción de línea de comandos --sql-mode = NO_BACKSLASH_ESCAPES o configurando sql-mode = NO_BACKSLASH_ESCAPES en el archivo de opciones del servidor (por ejemplo, my.cnf o my.ini , dependiendo de su sistema). (Error # 8378, CVE-2006-2753)

Consulte también el error n. ° 8303.

Viet
fuente
1
Esto se ha solucionado hace mucho tiempo.
Tu sentido común
2
También tenga cuidado que NO_BACKSLASH_ESCAPES introduce otras vulnerabilidades .
eggyal
2
Corregido en 5.1.11 - El enlace se rompió, aquí está el archivo: web.archive.org/web/20120501203047/http://dev.mysql.com:80/doc/…
Bastión