I found an easy way to make it so all templates by default are escaped. Since Backbone uses Underscore for it's templating engine, I googled around and found that you can customize the underscore delimiters using _.templateSettings
, described here on the Underscore site. Note that if you make sure all of your html is written out using these templates, then you're covered for all XSS. So don't skip using templates in some simple scenarios, use them to avoid XSS in those cases as well!
You can test it out using this fiddle: http://jsfiddle.net/vx0pw2n0/
So all I did was make it so both <%=
and <%-
are used to display escaped data by default. The evaluate tag <%
still remains, and can be used to output whatever HTML you want using the print
statement. I also introduced a new tag, <%cleanHtml
that can be used to output HTML without it being escaped, and without needing to say print(someVariable)
<script type="text/javascript">
//
// This is the important part - The part that changes what underscore uses
// for template delimiters.
//
_.templateSettings =
{
escape: /<%[=-]([\s\S]+?)%>/g,
interpolate: /<%cleanHtml([\s\S]+?)cleanHtml%>/g,
evaluate: /<%([\s\S]+?)%>/g
};
// Test it out
var t = _.template($('#t').html());
var html = t({ title: '<b>pancakes</b>' });
$("#target").html(html);
console.log(html);
</script>
<!-- Sample Underscore Template showing different ways of using it -->
<script id="t" type="text/x-underscore">
<div><%= title %></div>
<div><%- title %></div>
<div><%safeHtmlOnly title safeHtmlOnly%></div>
<div><% print(title) %></div>
</script>
<div id="target"></div>
Making this work globally
To get this to work globally, you may have to configure Underscore as a module, which can be done like so:
Implement as a dependency on Backbone
Configure Require.js modules
// When you initially setup require.js, add a new module to configure underscore
// Make it a dependency of backbone, so it'll always be loaded whenever
// backbone is used.
require.config({
shim: {
underscore: {
exports: '_'
},
backbone: {
deps: ['underscoreConfig', 'underscore', 'jquery'],
exports: 'Backbone'
},
jquery: {
exports: 'jQuery'
}
}
});
underscoreConfig.js
define(['underscore'], function (_) {
'use strict';
_.templateSettings =
{
escape: /<%[=-]([\s\S]+?)%>/g,
interpolate: /<%cleanHtml([\s\S]+?)cleanHtml%>/g,
evaluate: /<%([\s\S]+?)%>/g
};
return _;
});