2010-09-24 8 views
20

Dado ciertos conjuntos de caracteres multibyte, ¿estoy en lo correcto al asumir que lo siguiente no hace lo que estaba destinado a hacer?str_replace() en cadenas multibyte peligroso?

$string = str_replace('"', '\\"', $string); 

En particular, si la entrada estaba en un conjunto de caracteres que pueden tener un carácter válido como 0xbf5c, por lo que un atacante puede inyectar 0xbf22 para obtener 0xbf5c22, dejando un carácter válido seguido de una comilla doble sin comillas (") .

¿hay una manera fácil de mitigar este problema, o soy yo la mala interpretación del tema en el primer lugar

(en mi caso, la cadena va en el atributo de valor de una etiqueta HTML de entrada:? eco 'input type = "text" value = "'. $ string. '">';)

EDITAR: para el caso, ¿qué pasa con una función como preg_quote()? No existe un argumento de conjunto de caracteres, por lo que parece totalmente inútil en este escenario. Cuando NO tienes la opción de limitar el juego de caracteres a UTF-8 (sí, eso sería bueno), parece que estás realmente discapacitado. ¿Qué funciones de reemplazo y de cotización están disponibles en ese caso?

+0

Consulte [¿Se puede usar str strplace de forma segura en una cadena codificada en UTF-8 si solo se le asignan cadenas codificadas en UTF-8 como argumentos?] (Http://stackoverflow.com/questions/2652193/can-str-replace- be-safe-used-on-a-utf-8-encoded-string-if-its-only-given-valid) para leer por qué no necesita un mb_str_replace. – Lode

Respuesta

25

No, tiene razón: el uso de una función de cadena de un solo byte en una cadena multibyte puede causar un resultado inesperado. Usar la multibyte string functions lugar, por ejemplo mb_ereg_replace o mb_split:

$string = mb_ereg_replace('"', '\\"', $string); 
$string = implode('\\"', mb_split('"', $string)); 

Editar He aquí una aplicación mb_replace utilizando la fracción de unirse a la variante:

function mb_replace($search, $replace, $subject, &$count=0) { 
    if (!is_array($search) && is_array($replace)) { 
     return false; 
    } 
    if (is_array($subject)) { 
     // call mb_replace for each single string in $subject 
     foreach ($subject as &$string) { 
      $string = &mb_replace($search, $replace, $string, $c); 
      $count += $c; 
     } 
    } elseif (is_array($search)) { 
     if (!is_array($replace)) { 
      foreach ($search as &$string) { 
       $subject = mb_replace($string, $replace, $subject, $c); 
       $count += $c; 
      } 
     } else { 
      $n = max(count($search), count($replace)); 
      while ($n--) { 
       $subject = mb_replace(current($search), current($replace), $subject, $c); 
       $count += $c; 
       next($search); 
       next($replace); 
      } 
     } 
    } else { 
     $parts = mb_split(preg_quote($search), $subject); 
     $count = count($parts)-1; 
     $subject = implode($replace, $parts); 
    } 
    return $subject; 
} 

En cuanto a la combinación de parámetros, este La función debería comportarse como el singlebyte str_replace.

+0

No hay mb_str_replace en PHP –

+1

Su sintaxis para mb_ereg_replace() es incorrecta: requiere una expresión regular. Esperaba evitar un procesamiento más intenso requerido por este tipo de función, pero supongo que no tengo suerte. Necesito usar esto para TODO, incluso algo como preg_quote(), también, ¿no? A pesar de que las funciones ereg_ * normales están en desuso a partir de PHP5.3, ¿no se aplica lo mismo a las funciones mb_ereg_ *? – user456885

+1

@ user456885: '" 'es una expresión regular válida que describe el carácter' "' (tenga en cuenta que esto no es PCRE). ¿Pero por qué no usas la segunda variante de unión dividida? – Gumbo

3

Se puede utilizar cualquiera mb_ereg_replace especificando primero el juego de caracteres con mb_regex_encoding(). Alternativamente, si usa UTF-8, puede usar preg_replace con el modificador u.

+0

Desafortunadamente, no puedo limitarme a UTF-8, lo que creo que resolvería el problema. Supongo que mb_ereg_replace() es la única solución (?) ... pero parece ineficiente para un simple str_replace(). Tendría que llamarlo como un reemplazo para preg_quote() también, ¿eh? ... Además, sé que las funciones ereg_ * ahora están en desuso, ¿eso incluye también las funciones mb_ereg_ *? – user456885

+0

Los fragmentos de código son mejores que las oraciones IMPO – Trix

-3

Por lo que entiendo, gran parte de este tipo de inyección de cadena se resuelve con mysql_real_escape_string(); función.

http://php.net/manual/en/function.mysql-real-escape-string.php

+6

Esa es una función que está vinculada a un controlador de base de datos particular. No quiero confiar en las reglas del controlador de la base de datos para escapar de datos que ni siquiera van a la base de datos. Tampoco quiero exigir el uso de un controlador de base de datos si el código no usa una base de datos en primer lugar. – user456885

6

El código es perfectamente seguro con sanos multibyte-codificaciones, como UTF-8 y EUC-TW, pero peligroso con rotos unos como Shift_JIS, GB *, etc. En vez de ir a través de todos el dolor de cabeza y la sobrecarga para estar seguros con estas codificaciones heredadas, recomendaría solo apoyar UTF-8.

+1

no siempre es posible, especialmente para el tema muy popular de la minería de datos. –

+0

@TimoHuovinen: Para las aplicaciones en las que tiene que tratar con datos en codificaciones que no sean UTF-8, la solución más sencilla es volver a codificar durante la fase de entrada para que esté en UTF-8 en el momento de procesarla. –

+1

es más fácil decirlo que hacerlo :) por ejemplo, de esta manera descubrí una lista de aún no compatibles [caracteres admitidos por el navegador] (http://stackoverflow.com/questions/3565713/how-can-i-convert-html-character-references- x5e3-to-regular-utf-8/3566055 # 3566055). Los problemas con el uso de DOMDocument con UTF-8. Hay muchos problemas como este que harán de esta una pesadilla viviente para el recién llegado. [Como este] (http://stackoverflow.com/questions/9210473/how-to-convert-text-with-html-entites-and-invalid-characters-to-its-utf-8-equi) –

Cuestiones relacionadas