这篇文章主要讲目前互联网上get方法被不规范使用带来的一些安全漏洞。其中重点会讲get请求在账号登陆体系中被滥用的场景和攻击方式。
在客户机和服务器之间进行请求-响应时,两种最常被用到的方法是:GET 和 POST
GET - 从指定的资源请求数据
POST - 向指定的资源提交要被处理的数据
GET 方法的查询字符串是在 GET 请求的 URL 中发送的,常见的场景是地址栏请求和超链接。
根据HTTP规范,GET用于信息获取,是安全的和幂等的。安全的意思是get请求不会让服务端的资源或状态改变。幂等的意思是无论请求多少次,返回的结果都一样,都不会对服务端资源有任何副作用。
所以从被设计和现实中被使用的场景来看,get请求有如下特性
所以get请求的使用应该遵循
当你的实现不符合别人对你的预期,就可能产生漏洞,如
会被重放,导致服务端资源状态发生改变
get操作的csrf防护很难实施,因为get没有防伪造的需求,它的场景不一定配合你的防护。referrer信任可能被利用,token可能被偷。举个例子,一个塑料盒子,它本就不是被设计用来存钱的,你若非要用它存钱,并还要加上一把锁,效果肯定不会好。见下面例子:
常见的场景:一些使用了mvc框架的程序,直接用urlrewrite后的url来实现了增删改等操作
互联网上常见的敏感信息举例:
隐私信息
d7aK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6W2K9h3u0G2i4K6u0W2j5$3!0E0i4K6u0r3L8s2k6%4k6h3V1`.
大家可能觉得微博id不算隐私,但一旦你的id和某些操作绑定的时候,那就算是隐私了
校验信息
8acK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6E0M7q4)9J5k6i4N6W2K9i4S2A6L8W2)9J5k6i4q4I4i4K6u0W2j5$3!0E0i4K6u0r3j5$3N6A6i4K6u0V1j5X3W2F1i4K6u0r3K9r3!0E0k6g2)9K6c8Y4c8Q4x3@1c8Z5L8$3#2W2i4K6u0r3K9h3&6V1k6i4S2Q4x3U0k6S2L8i4m8Q4x3@1u0D9j5h3&6Y4i4K6y4p5P5X3S2Q4y4h3k6o6e0W2)9J5y4X3q4E0M7q4)9K6b7Y4c8G2K9$3g2F1i4K6y4p5x3K6M7I4y4K6j5%4y4U0b7K6
这是微博公众平台管理后台的首页,首页url里会包含csrf防护的token
认证信息
043K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8W2S2j5h3q4)9J5k6g2S2j5h3q4S2j5h3q4)9J5k6g2S2j5h3q4)9J5c8X3W2F1k6r3g2^5i4K6u0W2M7r3S2H3i4K6y4r3N6r3W2U0K9$3g2@1i4K6y4p5i4K6u0m8i4K6u0m8i4K6u0m8i4K6u0m8i4K6u0m8i4K6u0m8i4K6u0m8i4K6u0m8i4K6u0m8i4K6u0m8i4K6u0m8i4K6u0m8i4K6u0m8i4K6u0m8i4K6u0m8i4K6u0m8i4K6u0m8
8a6K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8W2S2j5h3q4)9J5k6g2S2j5h3q4S2j5h3q4)9J5k6g2S2j5h3q4)9J5c8X3W2F1k6r3g2^5i4K6u0W2M7r3S2H3i4K6y4r3k6%4y4A6k6q4)9K6c8q4)9J5b7g2)9J5b7g2)9J5b7g2)9J5b7g2)9J5b7g2)9J5b7g2)9J5b7g2)9J5b7g2)9J5b7g2)9J5b7g2)9J5b7g2)9J5b7g2)9J5b7g2)9J5b7g2)9J5b7g2)9J5b7g2)9J5b7g2)9J5b7b7`.`.
很多登录认证如单点登录,绑定第三方账号登录等会用get请求来完成登录
如果你的get请求中包含如上一些信息,那么你的敏感信息将会被偷被泄露,然后你会被搞!!!
隐私信息泄露举例

用户登录微博后,首页的url会含有用户ID信息。所以timeline上的链接的主人会通过referrer知道哪些用户访问了它。可能大家都不会在意,它可能会帮你逮微博马甲、捉奸在网……
比如如下场景:
某天你男友出差,长夜漫漫,你很无聊,写了一篇博客,记录下了盛夏夜中你此刻的心情。喝完咖啡,你正打算上床睡觉了,突然你又好奇想知道自己青春的文采已被多少人阅读。于是你打开电脑,登上服务器,去查看你博客的访问日志,从referrer中你发现,你的男朋友和你的男同事在凌晨一点,都访问了你发的链接,并且IP一样。这个时候,作为一个男子汉,你可能要考虑下,应该哭多大声才不会吵到邻居……当然,你还可以安慰自己,他们是一起在网吧通宵玩游戏
我还曾经用此方法帮人揪出了一些人的微博马甲。只要你够无聊,你还可以玩些别的,比如在用户打开的页面上再放上些兴趣爱好治病寻医类的广告,如果他点了,你就可能会知道她平时爱逛的是不是三里屯的优衣库了。
我不清楚微博的首页地址为何要这样设计,服务端若要读当前用户id,完全从当前会话中就可读取,而且从安全的角度考虑,也不应该会从url中读取用户id信息。那为什么要显示用户的id呢…
token信息泄露举例

如上图,这是微信公众平台后台管理员点击了网友发来的信息后的打开第三方页面的请求,referrer字段中的url中包含了管理后台的csrf防护的token
微信公众后台的操作大多是post,csrf的防护有token和referrer,但在每个页面的get请求中,也会含有这个token。这样的话token很容易被referrer偷,见上图,token已经发给了第三方域了。这样csrf的防护体系就被削弱了
顺便说一句,这个后台是https的,所以我们的链接也要是https的才会发送referrer。在网上申请个免费的https站点即可
好在这个问题目前没什么危害,管理后台的csrf防护是referrer和token都做了的,而且用户想给公众号发一个链接需要一些小技巧,直接发链接在后台是不可以形成链接的。
认证信息泄露举例——被referrer发到第三方

上图是现在的乌云的厂商用户的查看漏洞详情的临时页面,原来的页面是没有查看密码的,是可以通过地址栏里那个含有auth信息的get请求直接查看漏洞详情的
但某一漏洞详情页包含了一个优酷的视频,这个查看详情的链接会在优酷的视频页显示。因为优酷为了告诉用户展示来源,显示了referrer信息。这样这个漏洞详情的临时查看页面就可以被网友在网上无意撞见了,厂商的漏洞详情可能会被提前泄露。见下图

详情可参考 WooYun: 乌云某临时授权查看链接在某些极小可能性下有泄露的可能
然后我想看看这个查看漏洞的授权页在网上泄露了多少,去百度搜了下


一个月内泄露的乌云厂商用户的临时查看链接竟然有十二页之多,我觉得应该不可能全是厂商管理员分享出去的。所以我有了一个猜测,不一定是错的,那就是:乌云的所有get请求都已被百度云加速收集,用来帮助用户进行搜索的seo优化。
使用get请求认证的一些场景
Xss偷不了httponly的cookie了?
首先我们了解些背景知识,我简单介绍下单点登陆
下文中将大量出现如下示例站点
举例:用户访问0fdK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4m8S2M7%4y4H3L8%4u0@1i4K6u0W2N6$3q4F1k6%4A6Z5j5h3&6Q4x3X3g2U0L8$3#2Q4x3V1k6D9L8$3N6A6L8W2)9J5k6i4m8Z5M7q4)9K6c8Y4g2J5L8q4)9K6c8r3S2@1N6s2m8Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2@1z5e0W2&6i4K6u0W2j5$3!0E0i4K6u0r3j5g2)9J5k6i4m8Z5M7l9`.`.
B站检验A站是白名单域后,然后302跳转到
f38K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6i4b7&6z5i4W2Q4x3X3g2U0L8$3#2Q4x3V1k6S2i4K6u0W2M7r3S2H3i4K6y4r3N6r3W2U0K9$3g2@1i4K6y4p5i4K6u0m8i4K6u0m8i4K6u0m8i4K6u0m8i4K6u0m8i4K6u0m8
然后a.php用ticket参数去B站验证用户合法后,再给用户种认证cookie
偷认证信息的大概流程如下,后面会细讲。总之攻击的目的就是,拿到用户的ticket信息

互联网上常见的几个单点登陆场景,通行证或第三方站给的登陆凭的证使用的方式各有不同,分别该怎么偷
场景一,直接使用票据来做验证,get型csrf的token和此类似
79fK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4b7&6z5i4W2Q4x3X3g2U0L8$3#2Q4x3V1k6S2i4K6u0W2M7r3S2H3i4K6y4r3N6r3W2U0K9$3g2@1i4K6y4p5h3q4S2j5h3q4S2j5h3q4S2j5h3q4S2j5h3q4S2j5h3l9`.`.
服务端使用此ticket去sso验证此用户身份,然后在本域种认证cookie
偷的思路:
让我们构造的页面获取到凭证后请求我们控制的服务器上的资源,这样referrer里就有ticket信息了
偷的几种方式
示意图如下,如下是我画的一个chrome浏览器,地址栏里ticket参数会被包含到下面的一些元素的请求的referrer中

参考案例: WooYun: 微博上你点我发的链接我就可以登上你的微博(web版和app端均可两个漏洞一并提交)
场景二,当我们在一个app内打开其公司产品的一些链接,会被加上认证信息去让用户自动登陆
偷的几种方式
见场景一的各种方式
用户甚至会通过app的分享功能把认证信息分享到邮件或朋友圈。曾经遇过一个案例,一个活动推广页面在app内被打开后,被app加上了get参数去完成了自动登陆,因为页面要得到用户的一些相关信息。然后这个带着认证参数的推广页面会被用户分享出去,然后别人点击了这个链接,就登陆了分享人的账号
场景三,中间页接收ticket完成认证,然后用js跳转到我们的目标页c27K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4b7&6z5i4W2Q4x3X3g2U0L8$3#2Q4x3V1k6D9L8$3N6A6L8W2)9J5k6i4m8Z5M7q4)9K6c8Y4c8A6j5$3E0W2N6q4)9K6c8q4S2j5h3q4S2j5h3q4S2j5h3q4S2j5h3q4S2j5h3q4S2Q4x3U0k6S2L8i4m8Q4x3@1u0#2M7X3I4Q4x3@1c8Z5N6s2c8H3i4K6y4m8i4K6u0r3i4K6u0r3N6o6V1&6P5g2)9J5k6h3y4G2L8g2)9J5c8X3q4Q4x3X3g2H3K9s2l9`. 此时会种上认证cookie
然后页面会使用js跳转到 205K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4b7&6z5i4W2Q4x3X3g2U0L8$3#2Q4x3V1k6S2i4K6u0W2M7r3S2H3
location.href=“6d3K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4b7&6z5i4W2Q4x3X3g2U0L8$3#2Q4x3V1k6S2i4K6u0W2M7r3S2H3i4@1f1J5i4K6R3H3i4K6W2p5i4K6y4n7
参考示例:某绑定了微博账号后可以自动登陆的网站
偷的思路:
因为js的跳转,ticket已经通过referrer发给了a.php了,那我们只要让a.php成为我们控制的页面就可以了,恰好302跳转可以帮我们实现
偷的几种方式
场景四,中间页接收ticket完成认证,然后用302跳转到我们的目标页f02K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4b7&6z5i4W2Q4x3X3g2U0L8$3#2Q4x3V1k6D9L8$3N6A6L8W2)9J5k6i4m8Z5M7q4)9K6c8Y4c8A6j5$3E0W2N6q4)9K6c8q4S2j5h3q4S2j5h3q4S2j5h3q4S2j5h3q4S2j5h3q4S2Q4x3U0k6S2L8i4m8Q4x3@1u0#2M7X3I4Q4x3@1c8Z5N6s2c8H3i4K6y4m8i4K6u0r3i4K6u0r3N6o6V1&6P5g2)9J5k6h3y4G2L8g2)9J5c8X3q4Q4x3X3g2H3K9s2l9`. 此时会种上认证cookie
然后页面会再302跳转到 e66K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4b7&6z5i4W2Q4x3X3g2U0L8$3#2Q4x3V1k6S2i4K6u0W2M7r3S2H3
参考示例:好几个大的互联网网站……
偷的几种方式
这种情况是多个302的跳转,跳转路径如下
请求1:d10K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4m8S2M7%4y4H3L8%4u0@1i4K6u0W2N6$3q4F1k6%4A6Z5j5h3&6Q4x3X3g2U0L8$3#2Q4x3V1k6D9L8$3N6A6L8W2)9J5k6i4m8Z5M7q4)9K6c8Y4g2J5L8q4)9K6c8r3S2@1N6s2m8Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2@1z5e0W2&6i4K6u0W2j5$3!0E0i4K6u0r3j5g2)9J5k6i4m8Z5M7l9`.`.
请求2:d55K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4b7&6z5i4W2Q4x3X3g2U0L8$3#2Q4x3V1k6D9L8$3N6A6L8W2)9J5k6i4m8Z5M7q4)9K6c8Y4c8A6j5$3E0W2N6q4)9K6c8q4S2j5h3q4S2j5h3q4S2j5h3q4S2j5h3q4S2j5h3q4S2Q4x3U0k6S2L8i4m8Q4x3@1u0#2M7X3I4Q4x3@1c8Z5N6s2c8H3i4K6y4m8i4K6u0r3i4K6u0r3N6o6V1&6P5g2)9J5k6h3y4G2L8g2)9J5c8X3q4Q4x3X3g2H3K9s2l9`.
请求3:303K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4b7&6z5i4W2Q4x3X3g2U0L8$3#2Q4x3V1k6S2i4K6u0W2M7r3S2H3
偷的思路:
在xss中,用iframe包含单点登录的请求1,登录跳转后,我们通过src属性可以读到请求1的url,使用iframe.contentWindow.location.href可以读到跳转最后的请求3的url。但我们需要的是中间的请求2。所以我们想,可不可以让它跳到请求2后,不再继续跳转了,这样我们通过iframe.contentWindow.location.href就可以读到请求2的url了。这时候我想起,cookie超长的拒绝服务终于可以派上用场了
偷的方式
拒绝服务还有个好处,可以绕过某些ticket的防重放。因为有些票据在受害者端只要被使用后,可能我们盗取后也无法利用了。使用这种方式偷,可以让票据在受害者端不会被使用。
还有,根据path设置cookie可以精准的让我们的iframe停在我们想让它停的url上。
示例代码如下:
#!javascript
var iframe =document.createElement('iframe');
iframe.src="http://passport.wangzhan.com/login.php?url=608K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6i4b7&6z5i4W2Q4x3X3g2U0L8$3#2Q4x3V1k6S2i4K6u0W2M7r3S2H3";
document.body.appendChild(iframe);
for (i = 0; i < 20; i++) {
document.cookie = i + ‘=’ + ‘X’.repeat(2000);//可以根据需求设置path
}
iframe.addEventListener('load', function(){
document.write(iframe.contentWindow.location.href);
for (i = 0; i < 20; i++) {
document.cookie = i + '=' + 'X';
}
}, false);
场景五,跨域从通行证获取登陆ticket
形式为类似cb8K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6i4N6S2L8X3N6*7K9r3q4F1i4K6u0W2j5$3!0E0i4K6u0r3M7%4y4G2i4K6u0r3k6$3g2@1M7%4c8Q4x3X3g2H3K9s2m8Q4x3@1k6U0j5h3I4D9j5X3q4U0K9#2)9K6c8r3A6K6L8$3&6H3,然后通行证会返回个jsonp格式的数据,里面包含认证信息
参考案例 WooYun: 微博上你点我发的链接我就可以登上你的微博(web版和app端均可两个漏洞一并提交)
偷的几种方式
综上所述,get请求的滥用大家都没重视过,但综合一些小漏洞,可能会产生一些意想不到的大漏洞
修复方案其实很简单,不要使用get方法进行非读操作,不要使用get方法传输敏感信息,因为你不可能控制你所有页面不向第三方发起带referrer的资源请求,而且get请求很难保护。它只是个天真烂漫的孩子,你不要让它承载太多责任
在前几天的阿里安全峰会上,我讲了这个议题,最后的观众提问环节有人问使用https可不可以解决上面的问题。答案当然是不可以,https解决的只是客户端到服务端的传输加密防篡改。但get请求的数据在两个端,尤其是客户端,https是保护不了的。
至于单点登录问题的修复方案,有很多层面都可以去解决,比如不使用get,不让攻击者发起伪造的单点登录请求等等, 这些细节需要具体问题具体对待,这里就不细讲了。有需求的女网友可以私下找我交流,共同为互联网的安全学习进步