外观
CSRF 是什么,怎么防?
CSRF 是诱导已经登录的浏览器,向目标站点发出用户并未打算发出的请求。浏览器会自动带上该站点的 Cookie,所以服务器以为是用户本人。防御用 SameSite Cookie、CSRF 令牌,以及校验 Origin。
原理
攻击页面无法读取另一个源的响应,但可以发起请求:自动提交的表单、隐藏的图片地址。只要目标接口只靠 Cookie 认人,这个请求就会带登录态。
三层做法:
SameSiteCookie。Lax在跨站时不带 Cookie,但顶级导航的 GET 仍会带;Strict更严;None必须同时Secure。新浏览器对未声明的 Cookie 往往按Lax处理,不能只靠默认值,要显式设置。- CSRF 令牌。服务器把一段随机值放进页面或响应里,真正改数据的请求把它放在自定义头或表单字段里带回来。跨站表单加不了自定义头,读不到另一个源的令牌,所以伪造请求对不上。
- 校验
Origin或Referer。改状态的请求,来源应该是自己的站点。有些隐私设置会拿掉Referer,所以它是辅助。
改数据的接口不要用 GET。GET 可以被图片和链接触发。
追问
有了 XSS,CSRF 令牌还有用吗?
注入脚本跑在本源里,能读页面上的令牌,也能发带令牌的请求。CSRF 防的是「别的网站」。本源里的脚本要靠防 XSS 解决。
CORS 能防 CSRF 吗?
简单的跨站表单不需要通过 CORS 检查就能发出。CORS 决定的是脚本能不能读到响应,不是请求发不发得出去。见 跨域。
易错点
- 把 CSRF 说成「攻击者读到了用户的数据」。读响应是同源策略的事;CSRF 是借浏览器把请求发出去。
- 只在前端藏按钮没有用,接口自己要校验。
SameSite=Lax仍然允许顶层 GET 导航带 Cookie,所以 GET 不能改数据。