@浅谈CSRF
CSRF的定义
跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。
简单来说,CSRF是一种劫持受信任用户向服务器发送非预期请求的攻击方式。通常情况下,CSRF 攻击是攻击者借助受害者的 Cookie 骗取服务器的信任,可以在受害者毫不知情的情况下以受害者名义伪造请求发送给受攻击服务器,从而在并未授权的情况下执行在权限保护之下的操作。
在讲CSRF之前,先介绍一下网络请求的基础知识。
什么是认证
通俗地讲就是验证当前用户的身份,证明“你是你自己”。而体现在互联网中,就是服务器怎么知道现在发送请求的这个用户是有权限的用户,比如用户有没有登录,是通过账号密码,还是邮箱手机号?通常来说,我们认为当你知道某个应用账号的用户名密码,或者说你能收到手机验证码的时候,就认为你是账号的主人。
什么是凭证
实现认证和授权的前提是需要一种媒介(证书) 来标记访问者的身份
在现实生活中,每个人都会有一张专属的居民身份证,是用于证明持有人身份的一种法定证件。通过身份证,我们可以办理手机卡/银行卡/个人贷款/交通出行等等,这就是认证的凭证。
在互联网应用中,一般网站会有两种模式,游客模式和登录模式。游客模式下,可以正常浏览网站上面的文章,一旦想要点赞/收藏/分享文章,就需要登录或者注册账号。当用户登录成功后,服务器会给该用户使用的浏览器颁发一个令牌(token),这个令牌用来表明你的身份,每次浏览器发送请求时会带上这个令牌,就可以使用游客模式下无法使用的功能。
什么是 Cookie
- HTTP 是无状态的协议(对于事务处理没有记忆能力,每次客户端和服务端会话完成时,服务端不会保存任何会话信息):每个请求都是完全独立的,服务端无法确认当前访问者的身份信息,无法分辨上一次的请求发送者和这一次的发送者是不是同一个人。所以服务器与浏览器为了进行会话跟踪(知道是谁在访问我),就必须主动的去维护一个状态,这个状态用于告知服务端前后两个请求是否来自同一浏览器。而这个状态需要通过 cookie 或者 session 去实现。
- cookie 存储在客户端:
cookie是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。 - cookie 是不可跨域的:
每个 cookie都会绑定单一的域名,无法在别的域名下获取使用,一级域名和二级域名之间是允许共享使用的(靠的是 domain)。
那么在了解到浏览器请求的基础知识之后,我们再来具体描述一下CSRF攻击是如何工作的。
CSRF攻击实例
例如,一论坛网站A的发贴是通过 GET 请求访问的,点击发贴之后,网站会发送一个请求:
http://www.example.com/postmessage?title=标题&content=内容
这个时候,我们构建一个攻击网站B,网站中放入一个如下的image标签,其地址指向刚才所说的发贴接口
< img src=“http://www.example.com/postmessage?title=哈哈&content=被攻击了吧”>
当登录用户C进入攻击者B网站的时候,页面会自动向A网站发送一个请求,这个时候,由于用户C已经登录,cookie中携带A网站的用户认证信息,服务器端会认为这就是用户C自发发送的请求,这个时候,B网站就在C用户完全不知情的情况下,利用C用户的身份,完成了一次发帖请求,这也就是我们所说的CRSF攻击。
在这个攻击过程中,攻击者借助受害者的 Cookie 骗取服务器的信任,但并不能拿到 Cookie,也看不到 Cookie 的内容。而对于服务器返回的结果,由于浏览器同源策略的限制,攻击者也无法进行解析。因此,攻击者无法从返回的结果中得到任何东西,他所能做的就是给服务器发送请求,以执行请求中所描述的命令,在服务器端直接改变数据的值,而非窃取服务器中的数据。
如何防范 CSRF 攻击
-
关键操作只接受 POST 请求
-
验证码
CSRF攻击的过程,往往是在用户不知情的情况下构造网络请求。所以如果使用验证码,那么每次操作都需要用户进行互动,从而简单有效的防御了CSRF攻击。
但是如果你在一个网站作出任何举动都要输入验证码会严重影响用户体验,所以验证码一般只出现在特殊操作里面,或者在注册时候使用。
-
检测 Referer
常见的互联网页面与页面之间是存在联系的,比如你在 www.baidu.com 应该是找不到通往www.google.com的链接的,再比如你在论坛留言,那么不管你留言后重定向到哪里去了,之前的那个网址一定会包含留言的输入框,这个之前的网址就会保留在新页面头文件的Referer 中
通过检查 Referer 的值,我们就可以判断这个请求是合法的还是非法的,但是问题出在服务器不是任何时候都能接受到 Referer的值,所以 Referer Check 一般用于监控 CSRF 攻击的发生,而不用来抵御攻击。
-
Token
目前主流的做法是使用 Token 抵御 CSRF 攻击。
CSRF 攻击之所以能够成功,是因为攻击者可以完全伪造用户的请求,该请求中所有的用户验证信息都是存在于 Cookie 中,因此攻击者可以在不知道这些验证信息的情况下直接利用用户自己的 Cookie 来通过安全验证。要抵御 CSRF,关键在于在请求中放入攻击者所不能伪造的信息,并且该信息不存在于 Cookie 之中。可以在 HTTP 请求中以参数的形式加入一个随机产生的 token,并在服务器端建立一个拦截器来验证这个 token,如果请求中没有 token 或者 token 内容不正确,则认为可能是 CSRF 攻击而拒绝该请求。
具体流程简介: -
客户端使用用户名跟密码请求登录
-
服务端收到请求,去验证用户名与密码
-
验证成功后,服务端会签发一个 token 并把这个 token 发送给客户端
-
客户端收到 token 以后,会把它存储起来,比如放在 cookie 里或者 localStorage里
-
客户端每次向服务端请求资源的时候需要带着服务端签发的 token,把token 放到 HTTP 的 Header 里,服务端收到请求,然后去验证客户端请求里面带着的 token ,如果验证成功,就向客户端返回请求的数据。
总结
本文主要介绍了CSRF 的攻击原理和防御措施。当然,在 Web 安全领域,除了这种常见的CSRF攻击方式,还存在XSS,SQL 注入等其它攻击方式,本文不做详细介绍。最后,总结一下
CSRF攻击原理:
- 劫持受信任用户的cookie, 向服务器发送非预期请求的攻击
CSRF常见防御措施:
- 验证码
- Referer Check
- Token 验证