跨站请求伪造 CSRF(Cross-Site Request Forgery)
危害
盗用用户身份。以用户的名义进行各种操作。如:修改密码(账号盗取)、消费
原理
- 用户在浏览器中登录信任的站点 A(如:淘宝网)
- 站点 A 验证用户登录信息,成功后在浏览器 Cookie 中写入敏感信息
- 用户没有退出站点 A 的情况下,访问了危险网站 B
- 危险网站 B 在页面内发起访问站点 A 的请求(用户不知道的情况下),此时浏览器会携带站点 A 的 Cookie
- 网站 A 并不能知晓请求是来自危险网站 B
示例
- GET 方式
<img src="http://www.taobao.com/member?money=1000" />
可以看到,的确是携带了 cookie。应当避免敏感接口使用 get 方式请求
-
POST 方式
可以看到,也是携带了 cookie
如何防御?
-
敏感操作,必须使用 POST 请求。并不能真正防止 CSRF 攻击,但是能够提升 CSRF 攻击的成本。
-
使用验证码。每次敏感操作进行验证码校验,用户体验较差。
-
每次请求返回时,服务端在 setcookie 中返回一串伪随机数,并要求用户每次请求时参数中携带该随机数。原则上攻击方不能够获取到被攻击网站的 cookie,所以能够防御。但是存在特殊情况,如 XSS 攻击,导致用户 cookie 泄露
-
One-Time Tokens(每次不同的伪随机数)
a. get_token() 令牌生成函数
function getToken() { $token = md5(uniqid(mt_rand(), true)); return $token; }b. 将令牌放入 session
$_SESSION[TOKEN_NAME] = getToken();c. 在 Web 表单中使用隐藏域保存 token
echo '<input type="hidden" name="' . TOKEN_NAME .'" value="'. $_SESSION[TOKEN_NAME] .'" />';d. 服务端验证 token 令牌。需要注意的是,用户如果使用浏览器标签页打开两个一样的表单,则前一个表单的 token 会失效,考虑兼容的问题。