Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Safely Using JSON with html inside of the JSON in Django Templates

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.

like image 321
speedplane Avatar asked Jan 12 '13 05:01

speedplane


1 Answers

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 }};
like image 91
Flash Avatar answered Sep 30 '22 05:09

Flash