2010-09-24 14 views
20

Dato determinati set di caratteri multibyte, ho ragione nel ritenere che quanto segue non faccia ciò che era destinato a fare?str_replace() sulle stringhe multibyte pericoloso?

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

In particolare, se l'ingresso era in un set di caratteri che potrebbe avere un carattere valido come 0xbf5c, quindi un attaccante può iniettare 0xbf22 per ottenere 0xbf5c22, lasciando un carattere valido seguito da un doppio apice non quotate (") .

c'è un modo semplice per attenuare questo problema, o sono io incomprensione problema, in primo luogo

(nel mio caso, la stringa sta andando in l'attributo value di un tag input HTML:? echo 'input type = "text" value = "'. $ string. '">';)

MODIFICA: Del resto, che dire di una funzione come preg_quote()? Non c'è alcun argomento per questo, quindi sembra totalmente inutile in questo scenario. Quando NON hai l'opzione di limitare il set di caratteri a UTF-8 (sì, sarebbe bello), sembra che tu sia davvero handicappato. Quali funzioni di sostituzione e quotatura sono disponibili in questo caso?

+0

Vedere [È possibile utilizzare str_replace in modo sicuro su una stringa con codifica UTF-8 se ha come argomento solo le stringhe con codifica UTF-8 valida?] (Http://stackoverflow.com/questions/2652193/can-str-replace- be-safe-used-on-a-utf-8-encoded-string-if-its-only-given-valid) per leggere il motivo per cui non è necessario un mb_str_replace. – Lode

risposta

25

No, hai ragione: l'utilizzo di una funzione di stringa singola su una stringa multibyte può causare un risultato imprevisto. Utilizzare il multibyte string functions invece, per esempio mb_ereg_replace o mb_split:

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

Modifica Ecco un'implementazione mb_replace utilizzando la scissione join 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; 
} 

quanto riguarda la combinazione di parametri, questo la funzione dovrebbe comportarsi come il singlebyte str_replace.

+0

Non c'è mb_str_replace in PHP –

+1

La sintassi per mb_ereg_replace() è errata - richiede un'espressione regolare. Speravo di evitare l'elaborazione più pesante richiesta da questo tipo di funzione, ma suppongo di essere sfortunato. Ho bisogno di usare questo per TUTTO - anche qualcosa come preg_quote(), anche, giusto? Nonostante le normali funzioni ereg_ * siano deprecate da PHP5.3, la stessa cosa non si applica alle funzioni mb_ereg_ *? – user456885

+1

@ user456885: '" 'è un'espressione regolare valida che descrive il carattere' "' (si noti che questo non è PCRE). Ma perché non usi la seconda variante split-join? – Gumbo

3

È possibile utilizzare mb_ereg_replace specificando innanzitutto il set di caratteri con mb_regex_encoding(). In alternativa, se si utilizza UTF-8, è possibile utilizzare preg_replace con il modificatore u.

+0

Sfortunatamente non posso limitare a UTF-8, che penso possa risolvere il problema. Immagino che mb_ereg_replace() sia l'unica soluzione là fuori (?) ... ma sembra inefficiente per un semplice str_replace(). Dovrei chiamarlo come sostituto di preg_quote(), eh? ... Inoltre, so che le funzioni ereg_ * sono ora deprecate - include anche le funzioni mb_ereg_ *? – user456885

+0

I frammenti di codice sono migliori delle frasi IMPO – Trix

-3

Da quanto ho capito, gran parte di questo tipo di iniezione di stringhe viene risolta da mysql_real_escape_string(); funzione.

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

+6

Questa è una funzione collegata a un determinato driver di database. Non voglio fare affidamento su alcune regole del driver del database per sfuggire ai dati che non vanno nemmeno nel database. Inoltre, non voglio richiedere l'uso di un driver di database se il codice non utilizza un database in primo luogo. – user456885

6

Il codice è perfettamente sicuro con sane più byte-codifiche come UTF-8 e EUC-TW, ma pericolosa rotti quelli come Shift_JIS, GB *, ecc Piuttosto che passando attraverso tutte il mal di testa e il sovraccarico per essere sicuri con queste codifiche legacy, consiglierei solo il supporto solo UTF-8.

+1

non sempre possibile, soprattutto per l'argomento molto popolare del data mining. –

+0

@TimoHuovinen: per tali applicazioni in cui è necessario gestire i dati in codifiche non UTF-8, la soluzione più semplice è la ricodifica durante la fase di input in modo che sia in UTF-8 al momento della sua elaborazione. –

+1

più facile a dirsi che a farsi :) ad esempio in questo modo ho scoperto un elenco di caratteri non ancora supportati [browser supportati] (http://stackoverflow.com/questions/3565713/how-can-i-convert-html-character-references- x5e3-a-regular-utf-8/3566055 # 3566055). I problemi con l'utilizzo di DOMDocument con UTF-8. Ci sono molti problemi come questo che renderanno questo un incubo vivente per il nuovo arrivato. [Mi piace questo] (http://stackoverflow.com/questions/9210473/how-to-convert-text-with-html-entites-and-invalid-characters-to-its-utf-8-equi) –