A utility method for escaping HTML entities in JSON strings. Specifically, the &, > and < characters are replaced with their equivalent unicode escaped form - u0026, u003e, and u003c. The Unicode sequences u2028 and u2029 are also escaped as they are treated as newline characters in some JavaScript engines. These sequences have identical meaning as the original characters inside the context of a JSON string, so assuming the input is a valid and well-formed JSON value, the output will have equivalent meaning when parsed:
json = JSON.generate({ name: "</script><script>alert('PWNED!!!')</script>"}) # => "{\"name\":\"</script><script>alert('PWNED!!!')</script>\"}" json_escape(json) # => "{\"name\":\"\\u003C/script\\u003E\\u003Cscript\\u003Ealert('PWNED!!!')\\u003C/script\\u003E\"}" JSON.parse(json) == JSON.parse(json_escape(json)) # => true
The intended use case for this method is to escape JSON strings before including them inside a script tag to avoid XSS vulnerability:
<script> var currentUser = <%= raw json_escape(current_user.to_json) %>; </script>
It is necessary to raw
the result of json_escape
,
so that quotation marks don't get converted to "
entities. json_escape
doesn't automatically flag the
result as HTML safe, since the raw value is
unsafe to use inside HTML attributes.
If you need to output JSON elsewhere in your HTML, you can just do something like this, as any unsafe characters (including quotation marks) will be automatically escaped for you:
<div data-user-info="<%= current_user.to_json %>">...</div>
WARNING: this helper only works with valid JSON. Using this on non-JSON
values will open up serious XSS vulnerabilities. For example, if you
replace the current_user.to_json
in the example above with
user input instead, the browser will happily eval() that string as
JavaScript.
The escaping performed in this method is identical to those performed in
the Active Support JSON encoder when
ActiveSupport.escape_html_entities_in_json
is set to true.
Because this transformation is idempotent, this helper can be applied even
if ActiveSupport.escape_html_entities_in_json
is already true.
Therefore, when you are unsure if
ActiveSupport.escape_html_entities_in_json
is enabled, or if
you are unsure where your JSON string originated from, it is recommended
that you always apply this helper (other libraries, such as the JSON gem,
do not provide this kind of protection by default; also some gems might
override to_json
to bypass Active Support's encoder).
Please login to continue.