返回
Featured image of post CSRF 相关

CSRF 相关

go!

CSRF相关

简述

跨站请求伪造(CSRF),本质是诱使用户在已经认证成功的Web应用中执行非本意的敏感操作。

与XSS的异同:

XSS本质是html代码中的注入,利用的是Web应用对站内用户的信任;而CSRF则是通过伪装成特定网站的受信任用户去执行敏感操作。

XSS可获取用户Cookie等身份信息,而CSRF仅仅是模仿伪装,并没有获取用户身份信息。

原理

前提

  • Cookie值是从本地存储中取出并填充进数据包

  • 用户必须在同一个浏览器中点开链接

  • 目标后台身份验证机制不健全(仅有Cookie机制,缺少其他验证)

原理

当某个用户访问目标网站并认证成功获得Cookie后,攻击者通过伪造用户身份(利用已经获得的Cookie)向目标网站发起敏感请求,而目标网站认为此Cookie有效,误认为此请求是真实用户发起,便响应请求。

利用方式

GET

# 假设一个简单的修改密码的场景
http://example.com/haha?password1=123456&password2=123456&op=change
  • 直接构造URL,诱使用户更改密码
  • 短链接
  • 使用html标签实现无感触发
# 可配合XSS
<script src="http://example.com/haha?password1=123&password2=123&op=change"></script>
 
# style="display:none;"
<iframe src="http://example.com/haha?password1=123&password2=123&op=change" style="display:none;"></iframe>
 
# border="0" style="display:none;"
<img src="http://example.com/haha?password1=123&password2=123&op=change"
border="0" style="display:none;">

POST

POST方式下攻击者可提供一个存在HTML表单自动提交的页面。

<form action="http://example.com/haha?" id="csrf" method="POST">
        <input type="hidden" name="password1" value="123">
        <input type="hidden" name="password2" value="123">
        <input type="hidden" name="op" value="change">
</form>

JSON

JSON CSRF 与普通 CSRF 的区别在于 :

  • JSON 数据无法像 post 那样通过一般HTML表单进行构造
  • 且Content-Type 一般要求为 application/json,也无法通过表单构造

虽然 XMLHttpRequest、fetch 能构造出 JSON 请求,并且可以设置 Content-Type,但是无法跨域。

未验证或未严格验证 Content-Type 头 和 JSON 格式

  • 利用 JSON 格式容错性,例如加入=号仍然可以被解析
{"name": "haha", "age": 18}=
  • 伪造 JSON 格式
<input name='{"name":"haha","age": 18, "test":"' value='test"}' type='hidden'> 

严格验证 Content-Type 头 和 JSON 格式

一般情况下需要 Flash + 307 重定向(但实际情况下 Flash 一般都会被禁用)。

  • Flash 文件
  • 跨域 XML 文件(如果 flash 文件和 PHP 同域,则不需要)
  • 具有 307 状态码的PHP文件(307跟其他 3XX HTTP 状态码之间的区别就在于,HTTP 307 可以确保重定向请求发送之后,请求方法和请求主体不会发生任何改变)

参考:

JSON CSRF 1

JSON CSRF 2

防御方式

Referer头

限制Referer头必须为本站相关。当然该值可随意修改,因此不可信。

Token

CSRF 成功的原因就在于站点对于用户身份的辨别完全依赖于 Cookie,因此攻击者可以直接使用用户的 Cookie 来完成认证以执行敏感操作。

所以可在请求中加入一个随机产生的由服务端维护的Token,服务器接收到用户请求后会验证 Token,如果无 Token 或者 Token 不正确的请求都会直接丢弃。

注意:

既然是向页面内的请求中加入Token,就需要辨别内外链,如果是外链也加入Token,当攻击者诱使用户访问攻击者在目标站内所设的外链,则会泄露Token。

SameSite

同站判断规则:

根据 Mozilla 维护的公共后缀表(Pulic Suffix List)中的有效顶级域名(eTLD)+1的规则查找得到的一级域名是否相同来判断是否是同站请求。

Cookie的SameSite属性用来限制第三方Cookie。

有三个值:Strict、Lax、None

  • Strict

最为严格,完全禁止第三方Cookie。当跨站点时,任何情况下都不会带有Cookie。

  • Lax

相对放宽,但大多数情况也是不发送第三方Cookie。

其允许导航到目标网址的GET请求:

请求类型 示例 正常情况 Lax
链接 <a href="..."></a> 发送 发送
预加载 <link rel="prerender" href="..."/> 发送 发送
GET 表单 <form method="GET" action="..."> 发送 发送
POST 表单 <form method="POST" action="..."> 发送 不发送
iframe <iframe src="..."></iframe> 发送 不发送
AJAX $.get("...") 发送 不发送
Image <img src="..."> 发送 不发送
  • None

None是无限制。

Chrome升级到85版本后SameSite默认值由None变为Lax。用户可以修改其为None,但必须设置Secure属性(Cookie只能通过 HTTPS 协议发送),否则无效。

多次验证

对敏感请求加入验证码等验证机制,这样防御效果好,但会降低体验。

对于json格式CSRF的防御

严格校验 Content-Type 和 数据体格式

Licensed under CC BY-NC-SA 4.0
Built with Hugo
Theme Stack designed by Jimmy