Permissions-Policy 标头实际能锁定什么
一份实用指南,说明你可以限制哪些浏览器功能、哪些内容无法控制,以及如何在不破坏有用功能的前提下部署该标头。
目录
简短版
Permissions-Policy 是一个 HTTP 响应标头,允许站点限制对某些浏览器功能的访问:摄像头、麦克风、地理位置、全屏、支付、传感器,以及一长串较小的 API。
它不是通用的隐私护盾。它不会阻止所有跟踪、拦截 cookies、防止网络请求,或让第三方 JavaScript 变得安全。它擅长的事情范围更窄,但仍然有价值:减少你自己的页面和嵌入式 frame 可用的浏览器能力。
这很重要,因为现代网站是由分析片段、媒体嵌入、聊天小组件、同意管理器、广告脚本、地图、支付流程和内部实验拼接而成的。大多数这些组件并不需要访问强大的设备 API。好的策略会把这一点明确下来。
如果你已经在生产环境中审查标头,请把这项工作与对实际响应的直接检查结合起来。我们的指南 debugging redirects and HTTP headers in production 介绍了这里真正重要的习惯:检查浏览器实际收到的内容,而不是你的配置文件声称应该发生的事情。
Permissions-Policy 控制什么
该标头控制对具名浏览器功能的访问。准确列表会随着时间变化,因为浏览器 API 也在变化,但常见指令包括:
cameramicrophonegeolocationfullscreenpaymentusbbluetoothaccelerometergyroscopemagnetometerscreen-wake-lockclipboard-readclipboard-writepublickey-credentials-get- 早期讨论中的
interest-cohort,现在基本属于历史内容
一条指令可以不允许任何人使用某项功能,也可以允许当前 origin 使用,或允许选定的 origins 使用。例如:
Permissions-Policy: camera=(), microphone=(), geolocation=(self)
这表示摄像头和麦克风对该 document 及其嵌套浏览上下文禁用,而地理位置仅允许同源使用。
一个更宽松的示例:
Permissions-Policy: geolocation=(self "https://maps.example"), fullscreen=(self "https://video.example")
这允许你自己的 origin 和一个指定的地图提供商使用地理位置,并允许你自己的 origin 加上一个视频提供商请求全屏。
策略由浏览器评估。如果某项功能被禁止,使用该 API 的 JavaScript 应该失败或表现为不可用。具体失败方式取决于 API。有时 promise 会 reject。有时某项能力只是看起来无法使用。
它能在你自己的页面上锁定什么
在第一方页面上,Permissions-Policy 最有用的角色是护栏。它会降低意外代码或非预期代码的影响范围。
例如,一个营销页面很可能不需要麦克风、摄像头、Bluetooth、USB、运动传感器或支付 API。你可以全局拒绝这些功能:
Permissions-Policy: camera=(), microphone=(), bluetooth=(), usb=(), payment=(), accelerometer=(), gyroscope=(), magnetometer=()
这并不会让页面上的每个脚本都变得可信。但它意味着,如果标签管理器实验、被攻破的依赖项或粘贴进来的小组件尝试调用受限 API,浏览器不应授予其访问权限。
对于有许多贡献者的团队来说,这是一个有用的默认值。它把讨论从模糊的信任转向明确的能力。如果未来某个功能确实需要摄像头,就必须有人修改策略并解释原因。
这正是合适的阻力。
它能在 iframe 中锁定什么
围绕嵌入式内容时,该标头尤其有用。
浏览器已经将 iframe 视为独立的浏览上下文,但如果策略和 iframe 属性允许,嵌入的第三方内容仍然可以请求强大的功能。Permissions-Policy 让父页面可以设置上限。
例如,如果你的页面嵌入了视频播放器、支持小组件和地图,你可以避免让每个 frame 都访问所有功能。你可以只允许视频 frame 使用全屏,只允许地图 frame 使用地理位置。
这里需要理解两层:
- HTTP
Permissions-Policy标头为 document 设置策略。 - iframe
allow属性可以向某个 frame 委派特定功能,但只能在父策略允许的范围内进行。
一个简单的 iframe 可能如下所示:
<iframe src="https://video.example/embed/123" allow="fullscreen"></iframe>
如果你的标头完全拒绝全屏,iframe 属性无法覆盖该拒绝。如果你的标头允许该 origin 使用全屏,iframe 属性就可以进行委派。
这种层级关系是该标头值得使用的原因之一。它让平台或安全团队能够设置站点范围的边界,同时仍允许产品团队在需要的地方启用特定嵌入。
它不能锁定什么
这是团队有时会高估该标头的地方。
Permissions-Policy 不能替代内容安全策略。它不决定可以加载哪些脚本。它不会阻止脚本通过网络发送数据。它不会清理 HTML。它不会防止 XSS。它不会拦截表单垃圾信息。如果表单滥用是问题所在,应从 why your contact form is your biggest spam liability 中描述的机制入手,而不是从这个标头入手。
它也不能替代 cookie 治理。Cookies、本地存储、同意、第三方嵌入和浏览器跟踪保护是彼此独立的问题。如果你正在广泛审查隐私控制,cookie 领域值得单独过一遍;实际变更可参见 what changed for cookies in 2026 and what to do about it。
最重要的是,Permissions-Policy 不会让第三方 JavaScript 变得私密。如果你把第三方脚本加载到第一方页面中,它通常会以你的页面权限运行,受其他浏览器约束和你的安全标头限制。拒绝摄像头访问是好事。但这并不能阻止该脚本读取 DOM 内容、观察用户操作,或发起被允许的网络请求。
为此,你需要不同的控制措施:谨慎选择供应商、CSP、沙盒化 iframe、适用时使用 Subresource Integrity、数据最小化,以及乏味但必要的审查。
一个合理的默认策略
没有一个适合所有站点的通用标头,但大多数内容站点和营销站点都可以从限制性策略开始。
一个合理的第一版:
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(), usb=(), bluetooth=(), accelerometer=(), gyroscope=(), magnetometer=(), screen-wake-lock=()
然后只加回站点实际使用的功能。
例如:
- 使用 Payment Request API 的商店可能需要
payment=(self)。 - 位置查找器可能需要
geolocation=(self)或一个可信的地图 origin。 - 会议应用可能需要
camera=(self)和microphone=(self)。 - 视频较多的站点可能需要
fullscreen=(self "https://trusted-video.example")。
重要的是,不要从清单中复制一份巨大的策略就宣称完成。先从你的功能清单开始。哪些页面需要哪些浏览器能力?哪些嵌入需要委派?如果哪些功能被请求,会让人感到意外?
如何部署而不破坏功能
像部署任何其他生产标头一样推出它:有意识地进行。
1. 盘点功能使用情况
在代码库中搜索浏览器 API 调用,例如 getUserMedia、geolocation、requestFullscreen、PaymentRequest、Web Bluetooth、WebUSB 和 wake lock API。
然后检查第三方嵌入。视频、地图、支付和身份提供商的文档通常会提到所需的 iframe allow 值。
2. 从低风险环境开始
在 staging 中添加限制性标头并测试核心路径。注意浏览器控制台消息。浏览器通常会报告某项功能何时被 permissions policy 阻止。
3. 必要时使用页面级策略
如果你的产品有非常不同的页面类型,不要强行使用一个全局策略。博客、结账页、地图页和视频房间很可能需要不同的能力。
大多数 Web 服务器、框架和 edge 平台都可以按路径有条件地设置标头。这通常比为了一个功能削弱整个站点更干净。
4. 验证真实响应
CDN、反向代理、应用服务器和中间件可能会添加、覆盖、重复或剥离标头。请在浏览器 DevTools 中或使用命令行工具检查最终响应。
还要测试嵌入式上下文。顶层页面看起来正确,并不能保证 iframe 收到了你预期的委派。
5. 记录例外
每个被允许的功能都应该有负责人和理由。这听起来官僚,直到六个月后,没人记得为什么曾经把 geolocation 开放给一个页面上已经看不到的供应商域名。
常见语法错误
现代标头语法很紧凑,但也很容易稍微写错。
使用空括号拒绝某项功能:
Permissions-Policy: microphone=()
使用 self 表示当前 origin:
Permissions-Policy: geolocation=(self)
使用带引号的 origins 表示特定外部 origins:
Permissions-Policy: fullscreen=(self "https://video.example")
避免依赖旧的 Feature-Policy 示例,除非你有意支持旧版行为。旧标头使用不同语法,不应作为今天设计的基础。
还要记住,浏览器支持会因指令而异。浏览器可能支持该标头,但不支持某个特定功能指令。这是正常的。应把该标头视为纵深防御措施,而不是唯一的隐私或安全控制。
<!-- tool-cta:start -->
💡 试试这个: 使用 Get Headers 验证你的 Permissions-Policy 是否按预期传送,它会显示服务器正在发送的原始响应标头。
<!-- tool-cta:end -->
实际的隐私价值
Permissions-Policy 的隐私价值不在于让站点匿名或没有跟踪器。它做不到。
它的价值在于缩小对敏感浏览器能力的访问范围。位置、摄像头、麦克风、设备传感器、本地硬件 API 和支付流程都很强大。大多数页面并不需要它们。许多嵌入式组件永远不应该能够请求它们。
这是真实的改进。它减少意外提示,限制不必要的能力暴露,并为你的团队在新功能发布时提供一个可审查的具体产物。
这个标头的最佳状态是平淡无奇:默认限制,仅在面向用户的功能需要时放宽,并作为正常发布流程的一部分进行测试。