jQuery元数据插件和jQuery验证插件的主要问题

3
我正在使用无处不在的jQuery验证插件进行表单验证。它支持使用元数据插件为表单元素添加验证规则。
我正在使用这个功能。当验证器查找这些规则时,它会在元素上进行如下调用:
$(element).metadata()[meta] 

其中meta是存储这些规则的前缀。例如:

<input data-validate="{maxLength: 12}" name='foo'/>
的值将被设置为“validate”以捕获这些属性。但是这里有一个主要问题!
以下是元数据插件将数据属性解析为JSON的过程:
var getObject = function(data) {
    if(typeof data != "string") return data;
    data = eval("(" + data + ")"); //oh no!!!!!
    return data;
} 

if ( settings.type == "html5" ) {
    var object = {};
    $( elem.attributes ).each(function() {
        var name = this.nodeName;
        if(name.match(/^data-/)) name = name.replace(/^data-/, '');
        else return true;
        object[name] = getObject(this.nodeValue);
    });
} 

因此,最终发生的情况是metadata解析所有data-*属性,并尝试评估内容!一旦包含不包含json的数据属性,这将导致故障。
现在的问题是:
看起来metadata和validate都是“经得起考验”的插件。使用metadata插件会有这种已知的副作用吗?
我通常不喜欢修改插件代码以适应我的项目需求,但这似乎要么:
修复metadata插件以不盲目地评估内容,并且不使用eval或
修复validate插件以使用.data()而不是metadata插件
此外,除了修改metadata插件之外,还有其他方法可以解决这个问题吗?
发布赏金编辑:
我应该更清楚地表达,我对如何可能发生这种情况感到感兴趣。为什么一个如此重要的漏洞会存在于一个经典的验证插件和一个由Resig编写的无处不在的插件中。
修复很简单,我已经应用了它(我选择修改validate插件以在定义'meta'时使用$.data) - 我在这里给出150点的原因是想法为什么这仍然是一个问题(或者也许不是!)。

当然,这是一种奇怪的做法,因为HTML5中的表单已经内置了验证。我一直使用支持本地验证的浏览器中的本地验证,然后在旧浏览器中使用JS来模拟行为。 - Rich Bradshaw
2个回答

7

正如您发现的那样,“错误”(使用eval)在于元数据插件,而不是验证插件。

您链接的元数据插件版本实际上是一个分支;jQuery团队有官方仓库。如果您查看提交历史记录,您会发现自2007年以来没有进行任何真正的代码更新。该插件自2011年4月起已正式弃用

(John Resig在2008年7月发表了HTML5数据属性的博客文章,jQuery核心中的支持在1.4.3中到达,该版本于2010年10月发布。)

所以,我猜你的问题“这可能是怎么发生的”得到的答案是,你不应该再使用这个插件了 :-)
(更新:"官方" repo 现在已经归为“被 jQuery 基金会放弃的项目”。)
至于验证插件,除了一些 演示meta 选项之外,在文档中我找不到任何关于元数据插件的提及。正在进行添加 对 data- 属性的支持弃用元数据插件 的工作,所以希望下一个版本准备好后,元数据插件最终可以被弃用。

我很感激你详细的回答,特别是因为jQuery页面本身(在“学习”子域中!)仍然提倡使用metadata插件 - 尽管“官方存储库”已不再存在。 - EleventyOne
@EleventyOne 感谢您的评论;我已向 learn.jquery.com 的优秀(毫无疑问也很忙)团队提交了一张工单(https://github.com/jquery/learn.jquery.com/issues/409)。 - Jeffery To

0
data = eval("(" + data + ")"); //oh no!!!!

一种替换它的方式是

data = $.parseJSON(data); // oh yes!!!

实际上,当使用 .data() 方法获取“数据”时,它会尝试解析它,并且做得很好。因此最好使用它从元素中检索数据。之后,您将获得一个缓存对象,该对象将连接到节点并更快地给出属性值。

在这里 这是 metadata 插件的分支版本,它不会评估接收到的所有内容。有一件事情您必须知道。您应该引用字典的所有部分,就像在 JSON 中一样,但并不总是使用双引号。

{'foo': 'bar', "m": true, "b": 1}; // works
{foo: 'bar', m: true, b: 1}; // won`t work

2
为了避免编写有效的JSON元数据,您可以在解析getObject函数之前添加一行代码,例如 data = data.replace(/([a-zA-Z_$][\w$]*)\s*:/g,'"$1":');。其思想是找到对象键并给它们加引号。正则表达式可能需要稍作修改。 - jackwanders
我考虑过使用正则表达式来完成,但最后只做了引号替换以使其变得更容易。但还是谢谢你。 - Flops
我认为对于插件的用户来说,拥有有效的JSON是一个合理的要求;其他所有的都只是一种hack。 - mkoryak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接