2013-07-30 4 views
10

rotaie 3:Perché to_json esce automaticamente da Unicode in Rails 4?

{"a" => "<br/>"}.to_json 
=> "{\"a\":\"<br/>\"}" 

rotaie 4:

{"a" => "<br/>"}.to_json 
=> "{\"a\":\"\\u003Cbr/\\u003E\"}" 

PERCHE ???

sembra essere causa l'errore

Encoding::UndefinedConversionError: "\xC3" from ASCII-8BIT to UTF-8 

Quando i miei Rails 3 app tenta di analizzare JSON generato dai miei binari 4 app.

+0

Prova questa: JSON.generate ({ "a" => "
"},: ascii_only => true) – user2503775

risposta

9

PERCHÉ ???

Per difendersi da una debolezza comune nelle applicazioni web. Se si dice in una pagina HTML per esempio:

<script type="text/javascript"> 
    var something = <%= @something.to_json.html_safe %>; 
</script> 

allora si potrebbe pensare che stai bene perché hai JSON escape i dati che si sta iniettando in JavaScript. Ma in realtà non sei al sicuro: a parte la sintassi JSON hai anche la sintassi HTML circostante, e in un blocco di script HTML </ è la segnalazione in-band. In pratica, se @something contiene la stringa </script> hai una vulnerabilità cross-site scripting in quanto questo viene fuori:

<script type="text/javascript"> 
    var something = {"attack": "abc</script><script>alert('XSS');//"}; 
</script> 

Il primo blocco di script termina a metà strada attraverso la stringa (lasciando un errore di sintassi letterale di stringa non chiusa) e la il secondo <script> viene considerato come un nuovo blocco di script e viene eseguito il contenuto potenzialmente inviato dall'utente all'interno di esso.

L'escape del carattere < su \u003C non è richiesto da JSON ma è un'alternativa perfettamente valida e evita automaticamente questa classe di problemi. Se un parser JSON lo rifiuta, si tratta di un bug grave nel lettore.

Qual è il codice che sta producendo quell'errore? Non sono convinto che l'errore abbia a che fare con lo < -escaping, poiché si tratta di byte 0xC3 anziché 0x3C. Questo potrebbe essere indicativo di una stringa con contenuto codificato UTF-8 che non è stata contrassegnata come UTF-8 ... forse hai bisogno di un force_encoding("UTF-8") sull'input?

+5

Se davvero necessario disabilitare il JSON fuga (supponendo che la tua situazione sia sicura dall'iniezione) puoi farlo con: 'ActiveSupport.escape_html_entities_in_json = false' – elkelk

+0

Nel tuo esempio, perché chiama' .html_safe' not entity-escape "" a "</script >" ? Cosa fa questo metodo? – qntm

+1

'html_safe' fa effettivamente il contrario, contrassegna la stringa come contenente il grezzo mark che il chiamante ha già garantito è sicuro, quindi non necessita di ulteriore escape. Se * non * contrassegna la stringa 'html_safe', allora Rails lo scappa automaticamente (poiché Rails 3). – bobince

5

è possibile mantenere la stringa originale con JSON::dump:

JSON::dump "a" => "<br/>" 
=> "{\"a\":\"<br/>\"}" 

JSON::dump "a" => "x&y" 
=> {\"a\":\"x&y\"}" # instead of x\u0026y 

utilizzarlo con cura per le ragioni bobince citazioni e soprattutto di evitare con qualsiasi input generato dall'utente (o almeno assicurarsi che è santized).

Ecco un esempio che ho riscontrato in cui è un uso legittimo. Generazione di un argomento hash JavaScript in una funzione di supporto:

# application_helper.rb 

def widget_js(post) 
    options = { 
    color: ColorCalculator(post.color).to_rgb_hex, 
    ... 
    } 
    "third_party_widget(#{JSON::dump options});" 
end