How do you safely render JSON data in a django webapp?
On the server in django I generate JSON data and then render that JSON data in a django template. The JSON occasionally contains snippets of html. Most of the time, that's fine, however if the </script>
tag is inside the JSON data when it is rendered, it destroys the surrounding javascript.
For example...
On the server, in python I'll have this:
template_data = {
'my_json' : '[{"my_snippet": "<b>Happy HTML</b>"}]'
}
# pass the template data to the django template
return render_to_response('my_template.html', template_data, context_instance = c)
And then in the template:
<script type="text/javascript">
var the_json = {{my_json|safe}};
</script>
... some html ...
The resulting html works fine and looks like this:
<script type="text/javascript">
var the_json = [{"my_snippet": "<b>Happy HTML</b>"}];
</script>
... some html ...
However, you run into problems when, on the server, the JSON looks like this:
template_data = {
'my_json' : '[{"my_snippet": "Bad HTML</script>"}]'
}
return render_to_response('my_template.html', template_data, context_instance = c)
Now, when it's rendered, you'll get:
<script type="text/javascript">
var the_json = [{"my_snippet": "Bad HTML</script>"}];
</script>
... some html ...
The closing script tag within the JSON code is treated as closing the entire script block. All of your javascript will then break.
One possible solution is to check for </script>
when passing the template data to the template, but I feel like there is a better way.
Safely insert the JSON as a string, and then call JSON.parse on it
Use escapejs instead of safe. It is designed for outputting to JavaScript.
var the_json = '{{my_json|escapejs}}';
To get a JavaScript object you then need to call JSON.parse
on that string. This is always preferable than dumping a JSON-encoding into your script and evaluating it directly, for security reasons.
A useful filter to get python objects directly to the client that I use is this:
@register.filter
def to_js(value):
"""
To use a python variable in JS, we call json.dumps to serialize as JSON server-side and reconstruct using
JSON.parse. The serialized string must be escaped appropriately before dumping into the client-side code.
"""
# separators is passed to remove whitespace in output
return mark_safe('JSON.parse("%s")' % escapejs(json.dumps(value, separators=(',', ':'))))
And use it like:
var Settings = {{ js_settings|to_js }};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With