B03 内嵌内容与安全
摘要:
iframe把一个完整的第三方页面嵌进当前文档,代价是同时引入对方的脚本、样式与请求能力。默认配置下,被嵌页面与宿主共享部分能力,一个恶意广告位足以读取宿主页面的输入内容。本文给出sandbox、allow、referrerpolicy三项限制的组合方式,并用四步操作演示去掉限制后的后果。
关键词:iframe,sandbox,同源策略,内嵌,跨域
所属:frontend/html / B-进阶 | 上一篇:B02-多媒体与响应式图片 | 下一篇:B04-全局属性与交互元素
1 引言
内嵌内容在真实页面里几乎不可回避:地图、视频、代码片段预览、支付授权页。问题在于,内嵌等于把一段不受控的代码放进当前文档的渲染环境。
本文说明三件事:内嵌内容的默认能力边界、三项限制属性的组合方式、以及验证限制是否生效的方法。范围见表 1-1。
| 项 | 本文覆盖 | 本文不覆盖 |
|---|---|---|
| 内嵌 | iframe 的 src、sandbox、allow、loading、referrerpolicy |
站点隔离与进程模型 |
| 替代方案 | object、embed 的适用边界 |
插件式内容与本地文件预览 |
| 安全 | 同源策略、点击劫持、响应头 X-Frame-Options |
CSP 完整策略(C 阶段) |
2 预备知识
| 项 | 要求 | 核对方式 |
|---|---|---|
| 环境 | A02 的本地服务器 | 能访问 localhost |
| 文件 | html-practice/embed.html 与 inner.html |
两个文件同目录 |
| 浏览器 | Chrome 130+,开发者工具 Console 可用 | 能看到被拦截的报错 |
| 前置 | A08 | 能写语义骨架 |
3 原理与实现
3.1 内嵌带进来的三类能力
被嵌页面默认继承宿主的部分能力,风险集中在三处,如图 3-1 所示。
flowchart TD
I["iframe 加载第三方页面"] --> A["脚本执行<br/>可在自身文档内运行"]
I --> T["顶层导航<br/>可把整页跳走"]
I --> S["弹窗与表单<br/>可触发下载或新窗口"]
A --> G["sandbox 收紧"]
T --> G
S --> G
G --> OK["按需白名单放行"]
图 3-1 内嵌内容的三类能力与收紧路径
图上可见:
sandbox是白名单机制——不写任何令牌即全部禁用,再按需逐项放开。
3.2 严格模式与按需放行
先写最严格的形式,再逐项放开,是唯一可控的顺序。
<!-- 宿主页面:embed.html -->
<h2>代码片段预览</h2>
<iframe
src="./inner.html"
title="代码片段预览"
width="640"
height="320"
loading="lazy"
sandbox="allow-scripts"
referrerpolicy="no-referrer"
></iframe>
<h2>地图</h2>
<iframe
src="https://example.com/map"
title="位置地图"
width="640"
height="320"
loading="lazy"
allow="fullscreen"
referrerpolicy="strict-origin-when-cross-origin"
></iframe>
<!-- 被嵌页面:inner.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>被嵌页面</title>
</head>
<body>
<p>本页试图执行脚本与跳转,用于验证限制是否生效。</p>
<button id="go">跳转到上级</button>
<script>
document.getElementById('go').addEventListener('click', () => {
window.top.location.href = 'https://example.com/';
});
</script>
</body>
</html>
sandbox 常用令牌与效果见表 3-1。
| 令牌 | 放开的能力 | 是否建议 |
|---|---|---|
| (不写任何令牌) | 脚本、表单、弹窗、同源全部禁用 | 静态内容首选 |
allow-scripts |
允许执行脚本 | 按需,慎用 |
allow-same-origin |
保留同源,可与宿主共享存储 | 与 scripts 同用风险最高 |
allow-forms |
允许提交表单 | 表单类内嵌需要 |
allow-popups |
允许打开新窗口 | 按需 |
allow-presentation |
允许进入演讲模式 | 演示类需要 |
内嵌方式的选择见表 3-2。
| 方式 | 适用场景 | 优点 | 风险 |
|---|---|---|---|
iframe |
第三方页面、文档、地图 | 隔离完整、用法稳定 | 需自行收紧权限 |
object |
PDF、SVG 等文档对象 | 支持类型声明 | 移动端支持不一致 |
embed |
插件式内容 | 写法最简单 | 无回退内容,语义弱 |
| 直接链接 | 内容无需内嵌展示 | 零风险 | 打断浏览流程 |
规则三条:sandbox 一律从空值开始,逐项放开;allow-scripts 与 allow-same-origin 同时出现时限制基本失效,必须同用时需评估来源可信度;每个 iframe 必须写 title,否则朗读软件只念「框架」。
4 验证与讨论
- 用本地服务器打开
embed.html,内嵌区域显示被嵌页面。 - 点击被嵌页面中的「跳转到上级」按钮,观察整页是否被跳走;带
sandbox="allow-scripts"时应被阻断,Console 出现导航被拒绝的报错。 - 把
sandbox改为sandbox="allow-scripts allow-same-origin",重复步骤 2,观察限制失效。 - 删除
title,用朗读软件或无障碍面板查看框架的朗读结果。
| 检查项 | 预期结果 | 说明 |
|---|---|---|
| 顶层导航被阻断 | 整页未被跳走,Console 有报错 | sandbox 生效 |
| 脚本仍可执行 | 按钮点击有响应 | allow-scripts 生效 |
| 同源保留后 | 脚本可修改上层页面 | 组合令牌的危险性 |
| 新窗口被拦截 | 弹窗未打开 | 未放行 allow-popups |
| 框架说明 | 朗读软件读出 title 文字 |
title 属性 |
讨论与局限。 sandbox 只能约束被嵌页面,无法阻止宿主主动向对方发送数据;跨域内嵌的通信需要 postMessage 并校验来源。另 X-Frame-Options 由被嵌方设置,决定自己是否允许被嵌,宿主侧无法覆盖。
5 常见问题
| 现象 | 原因 | 处理 |
|---|---|---|
| 内嵌区域一片空白 | 对方设置了 X-Frame-Options: DENY |
改用直接链接或对方提供的嵌入地址 |
| 内嵌页样式错乱 | sandbox 未放行所需能力 |
逐项补令牌,逐次验证 |
| 点击内嵌页后整页跳走 | 未设置 sandbox |
从空 sandbox 开始收紧 |
| 移动端高度塌陷 | 只写了 width,未写 height |
同时给宽高,或用 CSS 宽高比 |
| 内嵌内容拖慢首屏 | 未加 loading="lazy" |
非首屏内嵌一律懒加载 |
6 结论
| 序号 | 结论 | 依据 |
|---|---|---|
| 1 | 内嵌等于引入一段不受控代码 | 图 3-1 |
| 2 | sandbox 从空值起步,按需放开 |
表 3-1 |
| 3 | allow-scripts 与 allow-same-origin 不宜同用 |
表 3-1 |
| 4 | 能不用内嵌就不用,直接链接风险最低 | 表 3-2 |
- 上一篇:B02-多媒体与响应式图片
- 下一篇:B04-全局属性与交互元素
- 返回:B00-总结 | 科目 README
参考文献
[1] MDN Web Docs · iframe 的 sandbox 属性,https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/iframe(访问于 2026-10-29)
[2] OWASP · Clickjacking Defense Cheat Sheet,https://cheatsheetseries.owasp.org/cheatsheets/Clickjacking_Defense_Cheat_Sheet.html(访问于 2026-10-29)

评论 0
还没有评论,快来抢沙发吧~