全称Cross-site request forgery
,即跨站请求伪造,在受害者毫不知情的情况下以其名义发起请求,比如改昵称,刷粉丝,添加系统管理员等。
如果经常用扫描器的话,可以发现一大堆CSRF漏洞,并且看着非常鸡肋。
实际上这个漏洞比较有用的地方(危害较大)是用来实现“帐户劫持”,可以参考曾经的乌云上的呆子不开口的账户劫持系列漏洞;以及一些后台没有做任何防护的野鸡CMS。
OAuth2.0
如果我们想要登录新浪微博,而微博又支持第三方登录例如QQ登录。那么我们就只能在微博上输入QQ账号和密码,同时这个网站也就知道了QQ账号和密码,这势必会产生一些安全问题,而OAuth
协议就是为了解决这些安全问题而产生的,Oauth2.0
是Oauth
协议的升级版。
以微博上用QQ登陆为例,使用的模式是Authorization Code
。
这里“微博”作为客户端,“QQ”作为服务端。
步骤一
在微博登录页点击QQ登陆的图标,会跳转到QQ的网页,提示“是否授权微博”获取你的“QQ头像”以及“QQ昵称”。
https://graph.qq.com/oauth2.0/show?which=Login&display=pc
&client_id=101019034
&response_type=code
&scope=get_info,get_user_info
&redirect_uri=https://passport.weibo.com/othersitebind/bind?site=qq
&state=CODE-gz-1F2ukL-448SQs-VFeXcvwk6Y0I4DO43f41e
其中有五个参数需要注意:
-
client_id
: 客户端id,标识是哪个客户端发起的请求,本例是“微博” -
response_type
: 授权类型,总共六种,这里是“授权码模式“ -
scope
: 授权的范围,这里是get_info,get_user_info
-
redirect_url
: 用户给予授权后,会携带授权码跳转到此地址,此处是https://passport.weibo.com/othersitebind/bind
-
state
:防御CSRF的token。每次授权请求,客户端都会生成一个state
,确保是本人发出的请求,并将其保存到cookie或session中。授权成功后,服务端原样返回state
,客户端将其与cookie或session中的值进行比对。
burp可以看到一堆请求,因为网页会拉起QQ客户端做快捷登陆,直到看到这个https://graph.qq.com/oauth2.0/login_jump
步骤二
接着向QQ发起一个POST请求
POST /oauth2.0/authorize HTTP/1.1
Host: graph.qq.com
Connection: close
Content-Length: 379
Content-Type: application/x-www-form-urlencoded
Referer: https://graph.qq.com/oauth2.0/show?which=Login&display=pc&client_id=101019034&response_type=code&scope=get_info%2Cget_user_info&redirect_uri=https%3A%2F%2Fpassport.weibo.com%2Fothersitebind%2Fbind%3Fsite%3Dqq%26state%3DCODE-gz-1HxYDK-2ei53a-oMXN8W54qO0CNyr9971a4%26bentry%3Dminiblog%26wl%3D&display=
Cookie: 一串内容
response_type=code&client_id=101019034&redirect_uri=https%3A%2F%2Fpassport.weibo.com%2Fothersitebind%2Fbind%3Fsite%3Dqq%26state%3DCODE-gz-1HxYDK-2ei53a-oMXN8W54qO0CNyr9971a4%26bentry%3Dminiblog%26wl%3D&scope=get_info%2Cget_user_info&state=&switch=&from_ptlogin=1&src=1&update_auth=1&openapi=80901010&g_tk=1929275414&auth_time=1559613258375&ui=66538B17-3A9C-4FD1-ACC4-8D326DCD9B4A
QQ服务器通过认证后,会生成一个授权码code
,重定向到redirect_url
,并且附上code
和state
。
HTTP/1.1 302 Moved Temporarily
Content-Length: 0
Location: https://passport.weibo.com/othersitebind/bind?site=qq&state=CODE-gz-1HxYDK-2ei53a-oMXN8W54qO0CNyr9971a4&bentry=miniblog&wl=&code=37D4420BA492FB4AD1A3EB9A70A4E029
步骤三
然后GET
请求下面的url
。在这里"微博"会向"QQ"比对state
是否一致(后台完成,用户不可见)。
https://passport.weibo.com/othersitebind/bind?site=qq&state=CODE-gz-1HxYDK-2ei53a-oMXN8W54qO0CNyr9971a4&bentry=miniblog&wl=&code=37D4420BA492FB4AD1A3EB9A70A4E029
state
验证通过之后,此时Oauth
验证已经结束。
“微博”生成一个alt
参数,带着这个参数重定向到sina.com.cn
。alt
参数如果校验通过,则种下cookie
https://login.sina.com.cn/sso/login.php?entry=qq&url=https%3A%2F%2Fweibo.com%2F&alt=ALT-NTI1NzEzMDI0Mg%3D%3D-1559613258-gz-4E9DA71B5000CCF8AD8D77E6FEEDF206-1&returntype=META&useticket=0&savestate=30
授权登陆劫持
如果攻击者伪造
redirect_uri
为自己的地址,然后诱导用户发送该请求,之后获取的凭证就会发送给攻击者伪造的回调地址。攻击者使用该凭证即可登录用户账号,造成授权劫持。
攻击流程:
- 需要用户授权,将网站帐户与第三方应用进行绑定;
- 用户已经登陆网站;
- 黑客构造恶意OAuth,引诱用户点击;
- 获取到
code
替换步骤三中URL的code
,如果state
参数没有做任何校验的话就劫持成功了。
直接修改redirect_url
就能成功的情况很少见,因为服务端会比对client_id
和redirect_url
是否对应。
突破方式:
- 利用
redirect_uri
规定的子域名中存在的漏洞:-
任意重定向,我们就可以从
referer
中看到code
,达到一样的攻击效果。 -
HTML注入,可以当作
GET XSS
的一种,页面引入了外部的恶意资源,从referer
获取code
。 - 或者找一个论坛,发个引入外部图片的帖子,将
redirect_url
修改成帖子的地址,从referer
获取code
。
-
任意重定向,我们就可以从
- 服务端对
redirect_url
的校验规则有问题导致绕过
auth.app.com.evil.com
evil.com?auth.app.com
evil.com?@auth.app.com
auth.app.com@evil.com
evil.com\auth.app.com
evil.com:\auth.app.com
evil.com\.auth.app.com
evil.com:\@auth.app.com
例子参考
未验证:wooyun-2013-045318 土豆网某处认证缺陷可劫持oauth_token
验证绕过:wooyun-2013-045327 绕过网易oauth认证的redirect_uri限制劫持帐号token
较为复杂实例:https://xz.aliyun.com/t/3514
绑定劫持
攻击者抓取客户端向服务端发起绑定请求构造恶意url,并诱骗已经登录客户端的用户点击(比如通过邮件或者QQ等方式)。认证成功后用户的帐号会同攻击者的帐号绑定到一起。
攻击流程:
- 用户在客户端网站处于登陆状态
- 攻击者通过OAuth授权用服务端小号登陆客户端网站
- 攻击者阻断授权过程,得到恶意URL
- 诱骗用户点击恶意URL,绑定了攻击者的服务端小号。另外劫持成功的条件,当然也是需要服务端不验证
state
。
参考实例:https://gh0st.cn/archives/2018-04-28/1
越权访问
scope权限控制不当带来的安全风险
参考:从“黑掉Github”学Web安全开发
防御方式:
- 验证 HTTP Referer 字段
- 在请求地址中添加一次性token
- 在 HTTP 头中自定义属性并验证
点击劫持
顾名思义,用户点击某个按钮,却触发了不是用户真正意愿的事件(亦是伪造了用户的请求)。
攻击者使用一个或多个透明的
iframe
,覆盖在一个网页上,然后诱使用户在该页面上进行操作,此时用户将在不知情的情况下点击透明的iframe
页面。攻击者既可以通过点击劫持设计一个独立的恶意网站,执行钓鱼攻击等;也可以与 XSS 和 CSRF 攻击相结合,突破传统的防御措施,提升漏洞的危害程度。
实例:https://www.cnblogs.com/lovesong/p/5248483.html
论劫持代码,绑定劫持那节的例子会更好些。
防御方式:
- javascript禁止内嵌
if (self == top) {
document.getElementsByTagName("body")[0].style.display = 'block';
} else {
top.location = self.location;
}
-
X-FRAME-OPTIONS
,一个专门解决点击劫持的HTTP头,有三个可选值:- DENY:浏览器会拒绝当前页面加载任何frame页面;
- SAMEORIGIN:frame页面的地址只能为同源域名下的页面;
- ALLOW-FROM origin:允许frame加载的页面地址;
拖拽劫持
目前很多浏览器都开始支持
Drag & Drop
的API。对于用户来说,拖拽使他们的操作更加简单。浏览器中的拖拽对象可以是一个链接,也可以是一段文字,还可以从一个窗口拖拽到另外一个窗口,因此拖拽是不受同源策略限制的。
"拖拽劫持"的思路是诱使用户从隐藏的不可见iframe
中"拖拽"出攻击者希望得到的数据,然后放到攻击者能控制的另外一个页面中,从而窃取数据。
目前除了《白帽子讲web安全》里面有一个实例,没看到比较新的例子。
参考
https://gh0st.cn/archives/2018-02-12/1
https://www.cdxy.me/?p=695