安全上下文:为什么强大浏览器 API 需要 HTTPS
了解安全上下文资格、权限与策略、来源边界,以及验证强大浏览器功能的确定性部署测试。
BotBrowser Team
安全上下文是浏览器能够合理信任页面来源完整性,并确认相关祖先上下文没有破坏这种信任的运行环境。W3C Secure Contexts 标准用这一分类限制可能暴露敏感数据或访问强大设备能力的 Web 平台功能。已部署的网站通常通过 HTTPS 获得资格,但安全上下文只是准入条件:它不会自动授予权限、覆盖嵌入策略、创建用户激活、保证 API 支持,也不能证明设备或远程服务会完成操作。
这也解释了常见问题:“为什么 API 在我的电脑上可用,部署后却不可用?”先检查来源以及完整的嵌入链,再检查浏览器是否公开相关接口、当前文档的 Permissions Policy 是否允许使用、用户或管理员是否授权,以及操作本身是否满足手势、设备和应用要求。
每一项属于不同边界,也可能独立失败。记录各项结果,才能把上下文资格、策略阻止和操作失败分别处理。
安全上下文的含义
W3C Secure Contexts 规范定义的是上下文分类,不是地址栏锁图标,也不是对页面所有脚本都安全的笼统保证。概括而言,当浏览器能确认来源及相关祖先可信时,潜在可信来源可以作为安全上下文运行。使用有效证书通过 HTTPS 提供的顶层页面是常见生产配置。若安全页面被不可信祖先嵌入,分类可能不同,因为祖先可能改变嵌入环境或其输入。
浏览器通过 window.isSecureContext 暴露当前全局对象的判定。它是有用的证据,但只回答一个较窄的问题,并不等于“功能可用”。它不会说明某个 API 是否已实现、策略是否许可、用户是否授权,或调用能否成功。页面应检查实际要用的能力,并处理 API 文档定义的结果,同时确认上下文资格。
浏览器会把部分开发来源视为潜在可信,即使它们没有公开可信证书。特别是 http://localhost 等回环来源通常可用于本地开发。这一例外便于迭代,不会让任意远程 HTTP 主机变成安全来源,也不应成为部署假设。MDN 安全上下文指南介绍了开发者模型和常见可信来源。浏览器细节可能变化,因此测试应记录实际来源和浏览器版本,而不是仅凭主机名硬编码结论。
摄像头、麦克风、地理位置、剪贴板、凭据操作等能力常被统称为“强大功能”,因为它们会影响隐私、设备访问或用户数据。但这并非一组要求完全相同的 API。具体规范分别规定条件:有些接口只在安全上下文中公开;有些还要求瞬时用户激活、明确权限、文档获得焦点或可见、特定文档策略、兼容硬件,或应用服务器返回可信结果。应查阅目标操作的规范,不要从其他 API 推断要求。
资格不等于授权
把浏览器功能拆成不同门槛更容易分析。首先,当前文档必须有资格公开仅限安全上下文的功能。其次,浏览器构建版本和平台必须实现所需接口。然后,嵌入关系和 Permissions Policy 必须允许该文档使用它。接着,用户、浏览器或受管设备的权限必须允许请求。最后,API 调用必须满足自己的调用条件,应用还要验证真正关心的结果。
| 门槛 | 检查项 | 记录结果 |
|---|---|---|
| 上下文 | window.isSecureContext 与最终来源 | 合格或不合格 |
| 策略 | 响应头与 iframe 的 allow | 允许或阻止 |
| 权限 | 用户、浏览器或受管设备的决定 | 已授予、已拒绝或待定 |
| 操作 | 接口、手势、硬件与应用结果 | 完成或失败 |
这些门槛不能互换。isSecureContext 为 true 不代表用户已授予位置权限。权限查询显示 prompt,后续请求仍可能被拒绝。JavaScript 方法存在,也可能因 iframe 的策略而无法使用。浏览器操作成功返回,应用后续请求仍可能失败。产品状态和测试报告应分别记录:上下文不合格、不支持、策略阻止、权限拒绝、用户取消、操作失败和应用完成,因为它们需要不同的后续处理。
Permissions Policy 规范允许顶层响应和 iframe 的 allow 属性指定哪些来源可以使用某些功能。响应策略是上限:子文档不能使用祖先已经禁止的能力。iframe 委派并不是权限授予;只有策略链允许时,它才使嵌入文档具备使用资格,用户决定及 API 自身条件仍然有效。因此,审查嵌入功能时,应同时查看顶层响应头、iframe 属性、子来源和目标功能规范。
文档来源也很重要。Web 安全策略通常以来源为范围,来源由 scheme、host、port 三元组构成。开发配置从 http 改成 https、更换主机别名或端口,可能产生另一个来源,其存储、权限、Cookie、Service Worker 注册和应用配置都彼此独立。不能把一个主机上的成功结论直接套用到另一个主机。带不透明来源的 sandbox iframe 是另一种边界;不要根据父页面显示的网址推断其 API 资格。
用户激活又是独立条件。即使页面安全且策略允许,某些 API 仍要求直接用户操作。不要在页面加载时调用需要用户激活的功能,再把拒绝误判为 TLS 问题。应把调用放在明确且可键盘操作的控件后,解释操作原因,并尽可能保留非 API 替代路径。权限提示应在用户理解选择的上下文中出现,且只在确有需要时请求。
localhost、HTTPS 与嵌入来源
本地开发和生产部署回答的是不同问题。许多浏览器实现会把 http://localhost 视为开发时可信来源,所以 API 可能在那里可用,而远程 HTTP 部署报告 isSecureContext === false。这是有意设计,不应通过修改应用逻辑来假设所有 HTTP 来源都安全。公开网站应通过 HTTPS 部署,使用有效证书和一致的规范主机名。
协议只是一个可能原因。本地与部署环境的主机名、端口、浏览器版本、权限历史、响应头、代理、功能开关和 iframe 结构也可能不同。比较完整 URL 和响应策略。不要通过 HTTP 重定向访问远程部署后,就假设初始导航状态代表最终页面:最终 HTTPS 文档加载后再断言,并记录其 location.origin 与 isSecureContext。
HTTPS 页面仍可能处于不安全或策略受限的嵌入链中。另一个 HTTPS 来源的 iframe 也可能是安全上下文,却没有某项功能的委派。跨源隔离、同源策略和 Permissions Policy 回答不同问题:隔离控制对某些共享能力和跨源资源的访问;同源策略限制不同来源之间的脚本访问;Permissions Policy 限制指定功能的使用。启用其中之一不会自动满足另外两项。
嵌入流程应逐文档验证并记录顶层来源、每个 frame 的来源、相关 frame 的安全上下文结果、Permissions-Policy 响应头以及 iframe 的 allow 声明。如果子文档确实跨源,只向目标来源委派明确的功能,并通过响应头限制其他来源。通配符比具体来源权限更宽,受控集成通常无需它。不要把 allow="*" 当作排错捷径;它会掩盖是哪一层边界让功能可用,也可能授权超出产品需要的能力。
混合内容也应作为独立部署缺陷处理。安全顶层页面若请求 HTTP 主动内容,浏览器可能阻止或限制该资源。应修复资源 URL 和服务器配置,而不是降低传输安全。地址栏锁标志不是充分的验收断言:页面应避免非安全请求加载预期资源,并在客户实际使用的顶层与嵌入结构中测试功能。
确定性的资格测试夹具
有用的回归夹具应证明一个小而明确的事实,不必调用摄像头、麦克风、定位或剪贴板,也不需要真实用户授权。下面的辅助函数创建可见结果、与测试预期比较,并在所有结果下清除临时 DOM。应在受控部署矩阵中运行:有效 HTTPS 来源预期为 true;普通远程 HTTP 来源预期为 false;localhost 则应按受测浏览器单独声明预期。这个断言只验证上下文分类,不代表某 API 已实现或获得授权。
async function checkSecureContext(expected) {
const host = document.createElement('section');
const status = document.createElement('output');
status.setAttribute('aria-live', 'polite');
host.append(status);
document.body.append(host);
try {
const actual = window.isSecureContext;
const passed = actual === expected;
status.textContent = `${passed ? 'PASS' : 'FAIL'}: expected secure context ${expected}; observed ${actual}`;
console.assert(passed, status.textContent);
console.assert(status.textContent.startsWith(passed ? 'PASS:' : 'FAIL:'));
return { passed, actual, visibleResult: status.textContent };
} finally {
host.remove();
}
}
// Set the expectation in test configuration, not from the value under test.
await checkSecureContext(true);
预期值必须来自夹具声明的部署情形,不能从被测的 window.isSecureContext 读取。生产测试框架可以从测试配置传入预期,并收集返回结果。测试 iframe 时,可在子文档运行同一夹具并用 postMessage 向父页面报告;父页面应先按预期子来源校验 event.origin,再接受消息。保持子测试页为合成页面,让父页面同时断言来源和子页面可见结果。这样可以把安全上下文分类与功能委派分开。
测试策略行为时,单独配置由自己控制的响应头和来源夹具,并确认子 frame 只获得预期委派。不要把会提示敏感授权的 API 当作唯一证明:提示被阻止可能来自策略、用户选择、浏览器设置、硬件缺失或实现规则。如果确需功能级冒烟测试,应检查接口,只在要求时由用户手势触发请求,把拒绝或取消作为独立结果,并保留替代操作。让这些断言与 isSecureContext 夹具分开,避免一个结果掩盖另一个。
测试矩阵应包含顶层 HTTPS 页面、预期嵌入来源、环境允许时的远程 HTTP 对照,以及开发者依赖的 localhost 流程。每种情况都注明精确 URL、预期安全上下文值、浏览器版本、响应策略、frame 关系和可见断言。HTTP 对照失败不是删除断言的理由,而是测试来源与声明预期不一致的证据。localhost 通过也不是生产证据。保留首次失败,然后通过 finally 或等价 teardown 清除夹具节点、临时数据和隔离的浏览器上下文。
部署、观察与回滚
发布前,应从公共入口沿着每次重定向和反向代理验证实际服务路径。为每个规范主机名部署有效证书,将 HTTP 重定向到 HTTPS,并确保最终文档来自预期来源。检查 Content Security Policy 和 Permissions Policy 响应头、iframe 的 allow 属性,以及暂存和生产之间不同的主机配置。若应用被客户嵌入,应写明准确子来源及所需委派,使集成方只需允许该来源。
在响应头和重定向稳定后先对暂存环境运行确定性夹具,再用同样断言验证生产候选版本。保留不含敏感数据的记录,包括 URL、浏览器构建、上下文结果、相关策略、子来源和应用可见结果。不要在夹具报告中保存凭据或原始权限提示。将 API 不可用、权限拒绝、策略阻止和下游事务失败分别记录。简洁的支持记录应让其他工程师无需访问用户配置文件即可复现同一来源链。
功能发布时也要一并部署回退路径。权限被拒、嵌入策略阻止功能或浏览器缺少接口时,只要产品能够提供替代方式,核心任务就应继续可用。例如,依赖位置的页面可以允许用户手动输入区域;文件操作可以提供常规下载;设备流程可以说明如何不使用设备继续。替代路径应保留已输入数据、支持键盘操作,并避免重复且隐藏的权限请求。不要把传输或配置问题误写成用户拒绝。
回滚应针对发生变化的组件。证书或重定向回归属于托管层;响应头回归属于服务器配置;iframe 委派错误属于嵌入集成;回退功能损坏属于应用发布。回退最小相关变更,恢复最后一个正常工作的 HTTPS 与策略配置,再使用同一来源和预期重跑夹具。绝不能为了回滚而通过普通 HTTP 提供敏感功能或大幅放宽策略。恢复旧应用路径时仍要保持安全传输不变量。
BotBrowser 可以验证什么
BotBrowser 支持为获授权的自有应用页面提供受控浏览器上下文,便于重复执行检查。团队可以用这些上下文在声明的来源上加载同一合成夹具,观察 isSecureContext、验证应用回退状态,并比较受支持浏览器版本中的可见结果。多账户隔离文档介绍了如何为不同浏览器流程分配隔离上下文。这适用于每轮都需要干净且范围明确的页面与测试状态的可重复 QA。
BotBrowser 无法让不安全的远程来源变可信、授予用户权限、覆盖 Permissions Policy、提供缺失的设备硬件,也不能保证所有浏览器和平台都提供某个 API。它不能代替W3C 安全上下文要求、应用自己的断言、证书运维或生产监控。受控上下文能证明的是已记录条件下浏览器可见的结果;HTTPS、响应头、嵌入配置和回退行为仍由网站所有者负责。解读成功测试时,应把这项能力与这些限制一并说明。
相关主题包括浏览器权限行为指南和浏览器 API 兼容性与回退指南。它们分别讨论权限状态和兼容性规划;本文聚焦文档是否具备尝试强大功能的资格。
每次验证都应保存最终来源、浏览器版本和策略快照,避免把旧环境的成功结果误用于新部署。