💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] # 概述 CSRF的全称是Cross Site Request Forgery,即跨域请求伪造。 ## 跨站点的请求 跨站点请求的来源是其他站点,如目标网站的删除文章功能 接收到恶意网站客户端发出的删除文章请求,目标网站应该区分请求来源。 ## 请求是伪造的 如果请求的发出不是用户的意愿,这个请求就是伪造的。 ## 一个场景 网站A有删除文章功能,通常是用户点击“删除链接”时才删除指定的文章,如www.a.com/blog/del?id=1。 用CSRF实现的步骤如下: * 在恶意网站B编写一个CSRF页面,如何发出GET请求到目标网站A? * 利用AJAX跨域时带上目标域的会话 * 用代码&lt;img src=[http://www.a.com/blog/del?id=1](http://www.a.com/blog/del?id=1) /&gt; * 然后欺骗已登录过目标网站A的用户访问CSRF页面 攻击过程有三个关键点:跨域发出一个GET请求、可以无JavaScript参与,请求是身份认证后。 # CSRF类型 按照请求类型可分为GET类型和PSOT类型的CSRF攻击。 若按照攻击类型分类,可分享HTML CSRF攻击、JSON HiJacking 攻击和Flash CSRF攻击。 ## HTML CSRF攻击 这一类是最普遍的CSRF攻击,HTML中能设置src/href等链接地址的标签都可以发起一个GET请求,如 * &lt;link href=""&gt; * &lt;img src=""&gt; * &lt;img lowsrc=""&gt; * &lt;img dynsrc=""&gt; * &lt;meta http-equiv="refresh" content="0; url="&gt; * &lt;iframe src=""&gt; * &lt;frame src=""&gt; * &lt;script src=""&gt; * &lt;bgsound src=""&gt; * &lt;embed src=""&gt; * &lt;video src=""&gt; * &lt;audio src=""&gt; * &lt;a href=""&gt; * &lt;table background=""&gt; * ... CSS样式中的: * @import "" * background: url\(""\) * ... 还有 通过JavaScript动态生成的标签对象或CSS对象发起的GET请求,而发出POST请求只能通过form提交。 ## JSON HiJacking 攻击 JSON HiJacking 基础非常经典,攻击过程是CSRF,不过是对AJAX 响应中 最长久的JSON数据进行的挟持攻击。 现代浏览器都提供了原生的方法 JSON.parse\(str\) 来转换为JS对象。低版本IE可通过引入JOSN3,不要使用eval。 在JS里可以为对象定义一些setter函数,这样的话就存在了可以利用的漏洞。 ``` window.__defineSetter__('x', function() { alert('x is being assigned!'); }); window.x=1; ``` 当利用&lt;script&gt;标签请求外部的一个JSON API时,如果返回的是数组型,就可以利用窃取数据。 比如有这样的一个API:[http://www.test.com/friends返回的数据是JSON](http://www.test.com/friends返回的数据是JSON) Array: ``` [{'user':'test01','age':18},{'user':'test02,'age':19},{'user':'test03','age':20}] ``` 在攻击页面上插入以下的代码,就可以获取到用户的所有的朋友的信息。 ``` <script> Object.prototype.__defineSetter__('user',function(obj) {alert(obj); } ); </script> <script src="http://www.test.com/friends"></script> ``` ## Flash CSRF攻击 # 危害 * 篡改目标网站上的用户数据 * 盗取用户隐私数据 * 作为其他攻击向量的辅助攻击手法 * 传播CSRF蠕虫 # 防御 ## 检查 http referer 根据 HTTP 协议,在 HTTP 头中有一个字段叫 Referer,它记录了该 HTTP 请求的来源地址。在通常情况下,访问一个安全受限页面的请求来自于同一个网站,比如需要访问 http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory, 用户必须先登陆 bank.example,然后通过点击页面上的按钮来触发转账事件。这时,该转帐请求的 Referer 值就会是转账按钮所在的页面的 URL,通常是以 bank.example 域名开头的地址。而如果黑客要对银行网站实施 CSRF 攻击,他只能在他自己的网站构造请求,当用户通过黑客的网站发送请求到银行时,该请求的 Referer 是指向黑客自己的网站。因此,要防御 CSRF 攻击,银行网站只需要对于每一个转账请求验证其 Referer 值,如果是以 bank.example 开头的域名,则说明该请求是来自银行网站自己的请求,是合法的。如果 Referer 是其他网站的话,则有可能是黑客的 CSRF 攻击,拒绝该请求。 <br> 然而,这种方法并非万无一失。Referer 的值是由浏览器提供的,虽然 HTTP 协议上有明确的要求,但是每个浏览器对于 Referer 的具体实现可能有差别,并不能保证浏览器自身没有安全漏洞。使用验证 Referer 值的方法,就是把安全性都依赖于第三方(即浏览器)来保障,从理论上来讲,这样并不安全。事实上,对于某些浏览器,**比如 IE6 或 FF2,目前已经有一些方法可以篡改 Referer 值**。如果 bank.example 网站支持 IE6 浏览器,黑客完全可以把用户浏览器的 Referer 值设为以 bank.example 域名开头的地址,这样就可以通过验证,从而进行 CSRF 攻击。 **同时,有以下场景无法获取referer**: 1. 直接在浏览器地址栏中输入地址; 2. 使用location.reload()刷新(location.href或者location.replace()刷新有信息); 3. 在微信对话框中,点击链接进入微信自身的浏览器; 4. 扫码进入QQ或者微信的浏览器; 5. 直接新窗口打开一个页面; 2017.8.3更新 新版本Chrome测试,新窗口页面依然有document.referrer 6. 从https的网站直接进入一个http协议的网站(Chrome下亲测); 7. a标签设置rel="noreferrer"(兼容IE7+); 8. meta标签来控制不让浏览器发送referer; <br> ## 使用一次性 token > token 是一段随机的数字字母值,经常出现在表单的隐藏项中,原理是 无法通过 ajax 获取到外域页面的 token 值(虽然可以通过 html 标签带动 ajax 跨域请求,如 &lt;img src='http://...'  onload="load\_ajax\_func\(\)"&gt;,但无法通过 javascript 读取返回的内容)。 > <br> ## 使用验证码(降低用户体验) > 当同域页面上有xss 漏洞时,可以通过 ajax 获取到其他页面的 token; > > token 如果出现在 get 参数中,也容易通过 refer的方式泄露; > > 此时只能通过验证码来防范csrf 了。 <br>