使用最新的主干和下划线库(1.0.0 / 1.4.4)我无法弄清楚为什么我的模板没有像我期望的那样转义。这是一个简化版本:
M = Backbone.Model.extend({});
V = Backbone.View.extend({
template: _.template("<%- attr %>"),
render: function() {
this.$el.html(this.template(this.model.attributes));
return this;
}
});
m = new M({attr: "<script>bad</script>"});
v = new V({model: m});
v.render();
console.log(v.el);
结果:
<div><script>bad</script></div>
显然,这并没有被转义。我已经验证了作为独立代码执行的模板正确转义:
T = _.template("<%- attr %>");
console.log(T({attr: "<script>bad</script>"}));
产生
的预期结果<script>bad</script>
所以某个地方的内容没有被转义。如果有人知道在哪里,或者更好的是,如何防止它,我将非常感激。
斯蒂芬
更新
想出来!虽然问题不在于控制台本身,但 mu 的回答确实指出了我正确的方向。为了解释,我需要详细说明上面的示例代码,以便更准确地反映我的上下文。该上下文实际上不是控制台输出,而是单元测试。我想验证我的代码是否正确防范XSS攻击,所以我编写了单元测试(使用mocha / sinon / chai / should):
v.$el.text().should.equal(m.escape("attr"));
该测试失败(意外),而下面的测试正在通过(我认为不应该这样):
v.$el.text().should.equal(m.get("attr"));
罪魁祸首证明是元素对象上的toString()
方法。 console.log()
使用的方法取消了内容。 jQuery在text()
函数中也(间接)使用该方法。
我不确定这在所有浏览器中都是通用的,但在我的情况下使用.innerHTML()
可以避免使用toString()
unescape。所以编写测试的正确方法是
v.el.innerHTML().should.equal(m.escape("attr"));
答案 0 :(得分:3)
我认为你的控制台过于“乐于助人”,令你感到困惑。如果我们仔细研究一下,我们就会看到究竟是什么样的诡计;我将切换到<b>
而不是<script>
,以避免将<script>
分成几块以避免混淆jsfiddle。
考虑一下:
M = Backbone.Model.extend({});
V = Backbone.View.extend({
template: _.template("<%- attr %>"),
render: function() {
this.$el.html(this.template(this.model.attributes));
return this;
}
});
m = new M({attr: "<b>bad</b>"});
v = new V({model: m});
v.render();
$('body').append(v.el);
$('body').append($(v.el).text()).append('<br>');
$('body').append($(v.el).html());
您会在页面上看到三件事:
<b>bad</b>
。bad
。<b>bad</b>
。我们希望看到attr
值 被转义。
console.log(v.el);
console.log(v.el.innerHTML);
现在在控制台中我们看到了:
<div><b>bad</b></div>
<b>bad</b>
但仔细观察第一行,您应该会看到<div>
和</div>
出现在紫色(或控制台用于DOM元素的任何高光颜色),而<b>bad</b>
为黑色(或者您的控制台用于纯文本的任何内容)。因此,attr
正在被正确转义,但您的控制台在显示之前正在解码。