¿Por qué to_json escapa unicode automáticamente en Rails 4?

Carriles 3:

{"a" => "
"}.to_json => "{\"a\":\"
\"}"

Rieles 4:

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

¿¿¿POR QUÉ???

Parece estar causando el error

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

Cuando mi aplicación Rails 3 intenta analizar JSON generado por mi aplicación rails 4.

¿¿¿POR QUÉ???

Para defenderse contra una debilidad común en las aplicaciones web. Si dices en una página HTML, por ejemplo:

  

entonces podría pensar que está bien porque JSON escapó de los datos que está inyectando en JavaScript. Pero en realidad no está seguro: aparte de la syntax JSON, también tiene una syntax HTML que lo rodea, y en un bloque de script HTML es la señalización dentro de banda. En la práctica, si @something contiene la cadena , tiene una vulnerabilidad de secuencias de comandos entre sitios, ya que esto sale:

  

El primer bloque de secuencia de comandos finaliza a mitad de la cadena (dejando un error de syntax literal de cadena no cerrada) y el segundo se trata como un nuevo bloque de secuencia de comandos y se ejecuta el contenido enviado por el usuario.

Escapar del < carácter a \u003C no es requerido por JSON pero es una alternativa perfectamente válida y evita automáticamente esta clase de problemas. Si un analizador JSON lo rechaza, es un error grave en el lector.

¿Cuál es el código que está produciendo ese error? No estoy convencido de que el error tenga que ver con el escape < , ya que se trata de byte 0xC3 en lugar de 0x3C. Eso podría ser indicativo de que una cadena con contenido codificado en UTF-8 no se haya marcado como UTF-8 ... ¿quizás necesite una force_encoding("UTF-8") en la entrada?

Puedes conservar la cadena original con JSON::dump :

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

Úselo con cuidado por los motivos que Bobince menciona y, en particular, evítelo con cualquier entrada generada por el usuario (o al menos asegúrese de que esté limpio).

Aquí hay un ejemplo que encontré donde es un uso legítimo. Generando un argumento hash de JavaScript en una función auxiliar:

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