2013-03-20 47 views
2

使用最新的主干和下划线库(1.0.0/1.4.4)我找不出我的模板为什么不像我期望的那样转义。下面是一个简化版本:Backbone.js/Underscore.js:为什么我的模板不能转义

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>"})); 

产生的

&lt;script&gt;bad&lt;&#x2F;script&gt; 

预期的结果所以某处内容越来越转义。如果有人知道在哪里,或者更好,如何防止它,我会非常感激。

斯蒂芬


更新:

想通了!虽然问题不是控制台本身,的答案确实指向了我的正确方向。为了解释,我需要对上面的示例代码稍加说明,以便它更准确地反映我的上下文。该上下文实际上并不是控制台输出,而是单元测试。我想验证我的代码是否正确防范XSS攻击,所以我写的单元测试(采用摩卡/兴农/柴/应):

v.$el.text().should.equal(m.escape("attr")); 

那个测试不及格(意外),而下面测试路过(我不认为它应该是):

v.$el.text().should.equal(m.get("attr")); 

罪魁祸首原来的元素对象上是toString()方法。该方法,即console.log()使用的方法可以使内容失效。在text()函数中,jQuery也(间接)使用该方法。

我不确定这在所有浏览器中都是通用的,但在我的情况下使用.innerHTML()可以避免使用toString() unescape。所以正确的方法来写我的测试是

v.el.innerHTML().should.equal(m.escape("attr")); 
+0

http://stackoverflow.com/faq#signatures – forivall 2013-03-20 19:51:42

回答

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()); 

你会看到页面上的三件事情:

  1. 一个文字<b>bad</b>
  2. A bad以粗体显示。
  3. 字面<b>bad</b>

这正是我们所期望看到的,如果attr转义。

然而,你正在看控制台。因此,让我们来看看在控制台以及在上述的JavaScript底部折腾了两件事情:在我们看到的这款控制台

console.log(v.el); 
console.log(v.el.innerHTML); 

现在:

<div><b>bad</b></div> 
&lt;b&gt;bad&lt;/b&gt; 

但在第一仔细观察行,你应该看到<div></div>显示为紫色(或者控制台用于DOM元素的任何颜色),而<b>bad</b>为黑色(或任何您的控制台用于纯文本)。所以attr正在正确逃脱,但您的控制台正在解码的东西显示之前。

演示:http://jsfiddle.net/ambiguous/5nYTd/

相关问题