Permissions-Policy通过allowlist精确控制API访问,语法为键值对形式,如"geolocation=(self \"https://maps.example.com\"), camera=()",需在Apache全局配置中用Header always set指令设置,且优先级低于iframe的allow属性。

Feature-Policy 已被弃用,必须改用 Permissions-Policy
Chrome 93+、Firefox 97+ 等主流浏览器已完全忽略 Feature-Policy 响应头,继续配置它不会产生任何效果。你看到的“配置生效”只是响应头被发出去了,但浏览器根本不读。实际生效的是 Permissions-Policy,两者语法不同、语义也不同——旧策略默认禁止,新策略默认允许,所以必须显式禁用敏感功能,否则等于没设。
Apache 中正确写 Permissions-Policy 头的语法和位置
在 Apache 配置中(如 httpd.conf 或 /etc/apache2/conf-enabled/security.conf),用 Header always set 指令设置,注意括号、分号、引号的嵌套规则:
Header always set Permissions-Policy "geolocation=(self \"https://maps.example.com\"), camera=(), microphone=()"
- 多个权限用逗号分隔,每个权限后跟括号包裹的来源列表
- 来源之间用空格分隔,
'self'必须加单引号(Apache 配置里需转义为\"https://...\") - 完全禁用某功能就写
camera=(),不是camera 'none'(那是旧 Feature-Policy 的写法) - 必须放在
<VirtualHost>外部或全局配置段,避免被 .htaccess 或子目录覆盖
为什么 header() 在 PHP 里设 Permissions-Policy 总是失败
不是 PHP 不支持,而是三个现实卡点:
Apache Superset 是一个广泛采用的开源 BI 平台,用于 SQL 探索、图表构建和仪表板交付。当代理需要查询仓库数据、组装仪表板或使用成熟的分析界面解释指标而不是临时笔记本代码时,此技能非常有用。
- 输出提前发生:哪怕文件开头有 BOM、空行、
echo "",header()就会静默失败 - CDN 或反向代理(如 Cloudflare、Varnish)可能过滤掉该头,或用自己策略覆盖
- 框架中间件(如 Laravel 的
TrustProxies)可能在你调用header()后又重写响应头
调试时别只看 PHP 代码有没有写,一定要打开浏览器开发者工具 → Network → Response Headers,确认实际发出的头内容。
iframe 的 allow 属性会覆盖 Permissions-Policy
如果页面里嵌了第三方 iframe,比如地图或支付组件,仅靠响应头控制不住它:
-
<iframe src="https://thirdparty.com" allow="geolocation 'self' https://maps.example.com">优先级高于响应头发的Permissions-Policy - 写成
allow="geolocation"(缺括号和来源)→ 浏览器直接拒绝,API 调用抛NotAllowedError - 多个指令必须用分号分隔:
allow="geolocation 'self'; clipboard-read 'self'; fullscreen ()",空格分隔已失效(Chrome 100+)
真正难的不是写对语法,而是理清「谁控谁」:响应头管整个页面上下文,allow 只管那个 iframe 自身行为,且后者胜出。漏掉这一层,策略就形同虚设。

















