为什么server返回json时必须是object,不能是array

在进行api请求时,返回的json,必须是object,而不能是array,这在很多框架里都被限定死了,当然通常你也可以自己json.encode(),然后返回一个字符串,来绕过框架的保护。那为什么api返回的结果一定要是对象,而不能是数组呢?

网上很容易找到《JSON Hijacking》,这里记录一下原理。

基于两点理由:

1. 以[]包起来的数组格式合乎js语法,能够被正确执行,而以{}包起来的对象,则不能被正确执行。

于是我们就可以伪造一个网站,然后将要攻击的目标网站的api请求作为js文件来引用:

<script type="text/javascript" src="http://example.com/api/xxx"></script>

如果返回结果是array,会被当成js成功执行,如果是object,执行就会失败,chrome下的console里,会出现红色的一行:

Uncaught SyntaxError: Unexpected token ':'

2. 通过重载js的set,我们可以截获特定key被set时的值

假如返回的结果如下:

[{
    "Id": 123,
    "Name": "zhangsan"
}, {
    "Id": 456,
    "Name": "lisi"
}]

我们想截获Id,举例代码:

<script type="text/javascript">
    Object.prototype.__defineSetter__('Id', function (obj) {
        send_to_remote_server('Id:', obj);
    });
</script>

基于以上两点,用户在访问一个伪造网站时,间接请求了目标站点的api,通过重载set,拿到了目标站点返回的结果。

解决方案两种,选择其一即可,显然第一条更容易办到:

1. 杜绝返回数组类型的json

2. api请求只接收POST请求,不接收GET请求

注意:现在的浏览器均避免了这种攻击方式,但老版本的一些浏览器依然存在这个问题。

发表于 06月13日 11:09   评论:0   阅读:400  



回到顶部

首页 | 关于我 | 关于本站 | 站内留言 | rss
python logo   django logo   tornado logo