同源策略与站点隔离:浏览器边界说明
解释 origin、文档访问、嵌入与站点隔离,帮助团队区分浏览器边界、网络可达性和服务器授权。
BotBrowser Team
同源策略限制文档或脚本读取、修改另一个 origin 的方式。
Origin 由 scheme、host 和 port 组成,任一部分变化都会形成新的边界。
它限制脚本可见的数据和文档关系,不是网络防火墙,也不能替代服务器授权。
站点隔离在浏览器条件允许时,把不同站点的文档放入分开的执行空间。
它能降低 renderer 被攻破后的影响,但不会决定 API 是否应该接受请求。调试时应分别记录浏览器观察、服务器响应和应用结果。
Origin 如何确定
WHATWG HTML origin 模型 对普通网络文档使用 scheme、host 和 port。默认端口、不同协议、别名主机和非默认端口都会改变边界。
例如 https://shop.example.test:443 与 https://shop.example.test 通常使用同一有效端口,而 https://app.example.test 和 https://cdn.example.test 即使属于同一组织,也可能是不同 origin。测试必须在 redirect 完成后记录最终的 location.origin。
部分文档具有 opaque origin,例如 sandboxed iframe、data: 文档和某些 blob: URL。不要因为熟悉的主机名、证书或父域名归属就推断信任。
Cookie、存储、权限和后台处理器的规则相关但不相同,报告要写清实际检查的状态存储。
Origin 比较应当是明确断言。接收其他窗口的消息时,先比较 event.origin,再验证消息数据结构和当前操作状态。这只能说明消息来自声明的 origin,不能证明远程应用已经授权操作。
同源策略允许什么
MDN 同源策略说明指出,一个 origin 的脚本对另一个 origin 的 DOM 和数据只能有限访问。跨源脚本可能导航窗口或提交表单,却不能任意读取目标 DOM 或响应字节;具体结果取决于 API 规范。
跨源请求可能已经到达服务器并返回 200,但 Fetch 仍会在没有合适 CORS 时隐藏响应。CORS 是响应共享契约,不授予服务器角色,也不使 endpoint 自动可信。需要判断响应可读性时,请看 CORS 浏览器边界指南。
窗口和 frame 的关系也受边界限制。使用 postMessage 时检查 event.origin、可用时检查 event.source 和消息结构;发送消息时使用具体 target origin。嵌入跨源页面不会赋予父页面读取其 DOM 的权限。
嵌入内容与消息通信
先在 redirect 后确认 parent 和 child origin,再明确需要的操作:显示、导航、表单、消息、响应读取或 DOM 访问。随后分别记录浏览器规则与应用授权检查。每个 frame 都要定义所有权和信任边界;Permissions Policy 和用户权限另行判断。
| 关系或操作 | 浏览器证据 | 安全结论 |
|---|---|---|
| 同源 DOM 访问 | scheme、host、port 全部相同 | 仍需检查状态和权限 |
| 跨源 frame 显示 | frame 加载并报告最终 origin | 显示不等于 DOM 访问 |
| 跨源响应读取 | Fetch 模式和 CORS headers | 可读性不等于服务器授权 |
| 窗口消息 | 期望的 origin、source 和 schema | origin 必须与消息数据一起验证 |
| 站点隔离文档 | 浏览器上下文和声明的版本 | 进程分离不证明应用安全 |
Redirect 可能改变最终 origin 以及 cookie、storage 和 CORS 行为。不要把 document.domain 当作新的集成方案;应使用显式消息或具备常规认证授权的服务器 API。
每个嵌入流程都应预先声明 frame 的所有者、允许的 target origin 和消息 schema 版本。这样可以把旧的 DOM 访问迁移为明确的消息通道,也不会因为域名熟悉就自动推断可信。
站点隔离增加了什么
Chromium 站点隔离概览说明它会把不同 site 的页面分隔到浏览器执行空间。Site 在某些平台规则中比 origin 更宽,进程分配还会受平台、内存、浏览器版本和文档关系影响。
站点隔离有助于降低 renderer 内存安全问题暴露的跨站数据,但不会把进程变成操作系统账号。服务器仍须认证请求、检查资源所有者、执行 CSRF 和状态转换校验。COOP、COEP 会影响窗口和资源关系,但它们与同源策略是不同控制。
不要把进程数量或 extension、service worker、特权页面的内部安排当成稳定契约。报告应声明浏览器家族、版本、操作系统和测试假设,公开结论应描述可观察的读取限制,而非内部架构。
Browsing context group 和 opener 关系也会影响隔离。跨站打开的窗口可能具有不同的脚本关系,COOP 与 COEP 还会改变窗口关系和资源加载;这些 headers 应与同源判断分开验证,并和页面最终行为一起记录。
可重复的策略 fixture
下面的 owned fixture 创建 control 和 candidate,检查消息 origin 并显示结果;它不读取第三方私密内容、不检查进程内部,也不发送 credentials。
async function checkOriginBoundary({ frameUrl, expectedOrigin, expectedMessage }) {
const frame = document.createElement('iframe');
const output = document.createElement('output');
output.setAttribute('aria-live', 'polite');
frame.src = frameUrl;
window.addEventListener(
'message',
event => {
if (event.origin !== expectedOrigin) return (output.textContent = 'UNKNOWN');
output.textContent = event.data === expectedMessage ? 'ALLOWED' : 'REJECTED';
},
{ once: true }
);
document.body.append(frame, output);
await new Promise(resolve => setTimeout(resolve, 5000));
return output.textContent || 'TIMEOUT';
}
await checkOriginBoundary({
frameUrl: 'https://owned-child.example.test/fixture',
expectedOrigin: 'https://owned-child.example.test',
expectedMessage: 'owned-fixture-ready',
});
Control 应报告期望的 origin 和消息,candidate 应显示独立的拒绝结果。若 navigation、frame 或 status 没有按时完成,返回 UNKNOWN 或 TIMEOUT,不要把它说成策略结论。保存最终 origin、浏览器版本、request log 和应用状态。
部署、监控与回滚
先建立 application、asset 和 identity host 清单。在 staging 使用最终 host、redirect 和响应 headers 运行 control 与 candidate,再检查登录、支付、客户 frame 和上传流程。CDN、身份提供商或浏览器版本改变后,要在新 context 中重复同一场景。
回滚应恢复之前的应用与策略组合,而不是简单删除 assertion。保留旧 headers、redirect map 和 frame 配置。不要为了让测试变绿而扩大 origin allowlist 或接受任意消息 origin;回滚时继续保持 HTTPS、认证和授权。
BotBrowser 可以验证什么
BotBrowser controlled browser contexts 可以运行获授权的自有 control/candidate fixture,隔离 synthetic state,并在声明的浏览器版本上比较可见 Fetch 结果。multi-account isolation 文档描述了上下文边界。BotBrowser 不会改变 origin、绕过策略,也不能证明远程业务已经完成。
BotBrowser 不提供服务器授权,不替第三方 API 配置 headers,也不会把进程观察变成应用安全保证。Server headers、authentication、authorization、CDN 和 application state 由各自系统所有者负责。作者:BotBrowser 团队。
相关边界还包括浏览器 storage、CORS 和 cross-origin isolation 指南:CORS 浏览器边界和 cross-origin isolation。它们分别解释状态分区、响应可读性和 isolation headers;本文聚焦 origin 身份、脚本访问和嵌入通信。
诊断应先建立 origin 清单并记录最终 URL,而不是先猜测浏览器进程。每一步都保存一个可观察证据和它不能证明的结论。
示例只使用 synthetic 地址,它们不代表真实服务。
Owned fixture 应使用 synthetic 数据、有限等待和新的 browser context。测试不需要真实 cookie、真实账号或私密响应。
报告要分别记录 network error、timeout、policy rejection 和 application rejection,避免把服务器路由问题误改成浏览器 header。
窗口消息要记录 sender、target origin 和 schema 版本。消息来自熟悉域名并不代表消息数据可以直接信任。
发布变更前,在同一浏览器版本上对照 control 和 candidate。CDN 或 redirect 改变后,要再次运行两边并保存 headers。
应用仍须独立验证 authorization 和状态转换;浏览器允许脚本读响应,并不等于业务已经授权或完成。平台报告应把进程隔离描述为特定版本的观察,不要把它写成所有浏览器都保证的安全属性。