之前已经写了两篇关于 CSRF
的文章,其中昨天的一篇手把手教你实现一次 CSRF 攻击 留下了防御的悬念,而今天这篇就是教导如何防御 CSRF
攻击
系列文章
- 手把手教你实现一次 CSRF 攻击
- [手把手教你防御 CSRF 攻击]()
- 面试题之 CSRF 攻击
CSRF 的触发方式
CSRF
本质上是 Cookie
的被利用(由于 session
的 sessionid
通常也是使用 Cookie
传递,因此也可以被视为原因之一)
通常触发 CSRF
的攻击有如下
- 表单提交触发(
POST
) Ajax
触发(POST
)GET
请求资源触发(比如图片或者iframe
)
CSRF
的最终目的是保证复杂请求(有副作用)能够作用到服务器(并不强制要求有服务器的响应至客户端)
副作用:指对数据库做出修改:使用GET请求获取新闻列表,数据库中的记录不会做出改变,而使用PUT请求去修改一条记录,数据库中的记录就发生了改变。
复杂请求定义:
请求以 GET, HEAD 或者 POST 以外的方法发起请求。或者,使用 POST,但请求数据为 application/x-www-form-urlencoded, multipart/form-data 或者 text/plain 以外的数据类型。比如说,用 POST 发送数据类型为 application/xml 或者 text/xml 的 XML 数据的请求。 使用自定义请求头(比如添加诸如 X-PINGOTHER)
一旦归属于复杂请求,就会在发送复杂请求之前发送一次预检请求(option
请求)
简单请求定义:
只使用 GET, HEAD 或者 POST 请求方法。如果使用 POST 向服务器端传送数据,则数据类型(Content-Type)只能是 application/x-www-form-urlencoded, multipart/form-data 或 text/plain中的一种。 不能使用自定义请求头(类似于 X-Modified 这种)。
防御方式
此处就是八股文背诵阶段
规范
遵循良好的规范可以避免攻击,这也是一种“防御方式”
对于有副作用的接口,尽可能去使用 POST
请求而不是 GET
请求,并且避免使用简单请求而是使用复杂请求完成,使用预检请求来拦截可能的跨域请求
JWT/CSRF Token
如何在根本上终结 Cookie
利用?不用不就行了?而对应的鉴权就是使用 JWT
,JWT
是属于 CSRF Token
的两种实现的一种,是基于加密解密实现的有效性认证
注意,JWT
是基于的公钥私钥模块进行的加密解密而不是随机字符串,下面就是的作用原理(HTTPS
也是使用的公钥私钥原理)
- 登录时,后台拿到用户的鉴权信息,并结合三部分组成
token
,分别为Header|Payload|Signature
,其中Header
说明加密算法等,Payload
是用户信息,通常为用户id
,而Signature
是使用自定义的私钥(PrivateKey
私钥只有你知道,泄露则被认为JWT
失效!)加密Header + Payload + PrivateKey
得到 - 鉴权时,
Base64
解密Header
和Payload
,得到签名的不可逆加密算法,比如HS256
,并使用私钥加上加密算法重新加密Header + Payload + PrivateKey
查看是否被篡改
通常登录后下发的 Token
由客户端存储,而浏览器中通常存在 LocalStorage
中,在发送请求时放在 Authentication
请求头中
参考资料
- [什么是JS跨域访问? - 前端私教年年的回答 - 知乎]https://www.zhihu.com/question/26376773/answer/2418353096
- 使用Express模拟并理解csrf攻击 - 大地dadi - 掘金
- 前端安全系列(二):如何防止CSRF攻击? - 美团技术团队