26

I'm building a Backbone.js application and am wondering what's the best way to deal with XSS respectively HTML escaping when using Backbone.js.

In the basic Todos example application from the official Backbone.js documentation, the data is not escaped. Since this data is used in the template to render the todo entries, it is possible to execute Javascript code by entering the following text (can be reproduced at the link above):

"><script>alert('xss');</script>

When using a REST server as storage backend, this XSS is persistent for every user.

How do you solve this problem?

My idea is to escape the data on the server, so the then returned data is safe to be used in a template. Do I then have to always use wait: true, to make sure no unescaped data is rendered? And for editing, add another attribute with the unescaped data, that can then be used to fill the textfield using .val()?

Or do you do none of this and escape the data on the client, before rendering the template?

hupf
  • 604
  • 1
  • 6
  • 10

2 Answers2

50

The Todo example is not the cleanest example. It uses underscore's template engine, as follows:

<input class="edit" type="text" value="<%= title %>" />

To correctly escape the HTML, use <%- instead of <%=:

<input class="edit" type="text" value="<%- title %>" />
Rob W
  • 341,306
  • 83
  • 791
  • 678
  • I think this is a wrong answer and should be completely opposite based on tags in https://ejs.co/#docs and https://stackoverflow.com/a/16184093 – Nitanshu May 29 '19 at 06:59
  • 2
    @Nitanshu The answer is correct. The Todo example uses [underscore's template engine](https://underscorejs.org/#template), which does use `<%-` to escape, and `<%=` to not escape. The fact that you can find a completely unrelated library with the opposite behavior does not affect the validity of this answer. Since posting this answer, the Todo example has been updated to follow my suggested approach (using `<%-` instead of `<%=`) following the PR at https://github.com/jashkenas/backbone/issues/1677 – Rob W May 29 '19 at 10:12
2

The standard way in backbone is to use model.escape(attribute).

From the backbone docs backbonejs.org/#Model-escape:

"Similar to get, but returns the HTML-escaped version of a model's attribute. If you're interpolating data from the model into HTML, using escape to retrieve attributes will prevent XSS attacks."

var hacker = new Backbone.Model({
    name: "<script>alert('xss')</script>"
});

alert(hacker.escape('name'));
Levsero
  • 591
  • 1
  • 4
  • 14