【API安全漏洞剖析】 FaceBook OAuth 漏洞 - 2020-03-01
【API安全漏洞剖析】 FaceBook OAuth 漏洞 - 2020-03-01
信息来源: https://www.amolbaikar.com/facebook-oauth-framework-vulnerability/
漏洞描述
第三方网站如(Instagram)是可以通过 Facebook 账号进行登录的, 具体登录逻辑就是利用 Facebook 提供的 SDK,使用 OAuth 授权进行登录。
具体来说就是用户登录 ins, 然后 ins 会根据 FaceBook 的 SDK 规范, 跳转到 Facebook 对应的登录页面, Facebook 登录完成之后, 返回一个 access_token 给 ins, 完成登录。
黑客在这个 OAuth 授权流程能够窃取 access_token ,从而达到接管用户账号的目的。
漏洞成因
在 Facebook 提供给开发者接入的 SDK 中, 有一个名为 “/connect/ping” 的登录服务端, 它是提供给第三方应用获取用户访问令牌的第三方端点, 具体逻辑是开发者通过编码在后台创建跨域通信的代理 iframe
, 再使用 window.postMessage()
方法接收令牌, 在接收令牌后, 该 API 会把链接跳转指向 Facebook 的 “XD_Arbiter” 下。 完整的 URL 为(以 ins 为例):
1 | https://www.facebook.com/connect/ping?client_id=APP_ID&redirect_uri=https://staticxx.facebook.com/connect/xd_arbiter.php?version=42#origin=https://www.instagram.com |
这里的 APP_ID
是第三方应用在 Facebook 注册时生成的应用 ID 值。
攻击者发现这里的 xd_arbiter.php?version=42
可以被篡改成 xd_arbiter/?version=42
, 然后在此基础下, 能够将目录附加到后面实现资源访问。
在这里由于通过上述目录获取到的 access_token
的相关值都是哈希片段, 很难去还原, 但是攻击者在 page_proxy
目录中发现了一个名为 7SWBAvHenEn.js
的 js 文件, 这个文件中包含如下内容:
1 | var frameName = window.location.href.split("#")[1]; |
第一行代码会获取 URL 请求参数中 #
后面的内容, 将它赋值给 frameName
, 然后调用 window.parent.postMessage
转发来自 frameName
发送的内容, 这里的 *
代表他可以接收任意源的请求。
然后攻击者构造 URL 为:
1 | https://staticxx.facebook.com/connect/xd_arbiter/r/7SWBAvHenEn.js?version=42 |
就可以穿越访问到这个文件, 再通过 #
去指定源, 就可以拦截该源发送回来的 access_token
.
这个 js 文件能够被攻击者利用, 原因如下:
- 攻击者能够通过资源附加访问到这个文件.
postMessage()
方法会发送未加密的令牌.*
允许了攻击者能在自己的源 ip 下请求并获取响应.- API 请求中没有验证
X-Frame-Options
标题,导致能够在xd_arbiter
中嵌入跨域嵌套postMessage()
回显的窗口. window.parent
下的方法不用与用户交互, 不需要关心window.open
或任何onClick
事件.
漏洞劫持
最后攻击者重写 Custom_SDK.js
1 | var app_id = '124024574287414', |
实现跨域攻击, 接管账户.
启示
作为防守方, 仅仅使用 URL 白名单来防御是不够的, 在面对跨域通信, 不同设备甚至浏览器的情况下, 即使使用了 X-Frame-Options
来防止跨域请求, 也有可能会因为兼容性问题产生漏洞.
在这里的启示就是, 应用设计时, 在实现功能的前提下, 要尽可能遵循简单原则, 参考标准协议实现流程, 线上环境不使用的文件, 要尽快清除.