HTTP 中的 policy:浏览器是一台 PDP
打开浏览器的 Network 面板,会看到许多带 Policy 字样的响应头:Content-Security-Policy、Permissions-Policy、Cross-Origin-*-Policy……它们并非杂乱无章的开关,而是同一件事的不同侧面:服务器声明策略(PAP),浏览器当场判 permit /
deny(PDP)并执行(PEP)。而且它们大多能精确解码回 授权请求 的那个四元组——只不过其中的 principal(who)是 origin:scheme + host + port。
browser.decide(origin, load / fetch / use, resource / feature) → allow | block
注 · 地基是同源策略(Same-Origin Policy),它是整个 web 的 default deny——默认情况下,A 源的脚本读不到 B 源的响应、碰不到 B 源的 DOM。那些 *-Policy 头,要么是放宽这条默认拒绝(CORS),要么是在它之上再收紧(CSP / Permissions-Policy)。它们和
组合算法 一脉相承:先定默认决策(deny),再用显式规则增删。
1 · CORS:服务器声明「谁能跨域读我」
跨域请求里,who 是请求方 Origin、action 是 HTTP method、what 是目标资源。服务器用一组 Access-Control-Allow-* 响应头声明它的放行策略,判定却发生在浏览器端。
https://api.example,请求与服务器策略变化时浏览器的 CORS 判定。可调 Origin、method、凭据与三个 Allow-* 响应头,观察 HTTP 交换与结论。
警示 · 三个常被误解的点。其一,简单请求(GET / HEAD / 简单 POST)没有预检——浏览器照样把请求发给服务器,只是当 CORS 不通过时拦截 JS 读响应;也就是说副作用可能已经发生,CORS 不是服务器侧的访问控制,真正的鉴权仍要服务器自己做。其二,非简单请求(PUT/DELETE、自定义头、JSON body)先发
OPTIONS 预检,预检不过,真正的请求根本不发。其三,凭据请求下 Allow-Origin: * 无效,必须回显具体 origin。
2 · CSP:文档声明「谁能往我身上加资源」
Content-Security-Policy 换了个轴:who 是子资源的来源(origin / nonce / hash)、what 是资源类型(由 directive 表示:script-src / img-src / connect-src……)、action 是 load / execute。它是一份白名单策略,未声明的 directive 回退到 default-src。
注 · 三个要点。默认回退:script-src 没写就用 default-src;default-src 也没写,这类资源就不受限。多份 CSP 等于 deny-overrides:一个响应可带多份 CSP(头 + meta、或多个头),浏览器取交集——每一份都必须放行才放行。Report-Only 等于
dry-run:Content-Security-Policy-Report-Only 不拦截、只上报违规,相当于「permit 但附带 obligation:上报」的审计/演练模式。
3 · 同一个模式的其他头
识别出「谁(origin)· 对什么 · 做什么 → 准/拒」这个骨架后,其余安全头便都易于理解了。
-
Permissions-Policy(前身 Feature-Policy):who 是文档 / iframe 的 origin,what 是强能力(
camera/geolocation/fullscreen),action 是使用。语法geolocation=(self "https://trusted.example")就是一条放行名单,camera=()是 deny-all。还能通过 iframe 的allow属性委派给子框架。 - Cross-Origin-Resource-Policy(CORP):资源侧声明「谁能把我当子资源嵌入」(
same-origin/same-site/cross-origin)——what 是这个资源,who 是嵌入方 origin。 - Cross-Origin-Opener-Policy(COOP)/ Embedder-Policy(COEP):一对用来开启跨源隔离的策略,决定本文档与被打开窗口 / 被嵌入资源的关系,换取
SharedArrayBuffer这类高能力。本质仍是「在什么 origin 关系下,准不准这么干」。 - Strict-Transport-Security(HSTS):「今后只准用 HTTPS 访问我」——action 是用 http 访问,decision 是强制升级 / 拒。
4 · 一张表收束:HTTP policy 头映回四轴
| 策略 | who | what | action | 默认 / 组合 |
|---|---|---|---|---|
| Same-Origin Policy | 请求方 origin | 跨源响应 / DOM | read | default deny |
| CORS | Origin 头 | 目标 URL | HTTP method | 显式 allow 才放宽 SOP |
| CSP | 子资源来源 | 资源类型 (directive) | load / exec | 白名单 + default-src 回退;多份取交集(deny-overrides) |
| Permissions-Policy | 文档 / iframe origin | 强能力 feature | use | allowlist,可委派 |
| CORP / COOP / COEP | 嵌入方 / 打开方 origin | 资源 / 文档 | embed / open | 按 origin 关系判定 |
建议 · HTTP 的安全头不是一组需要死记硬背的规则,而是同一个授权函数在浏览器中的实例——将 origin 视为 principal,先 default-deny,再用响应头声明的规则放宽或收紧。面对任何一个 *-Policy,先问「它的 who / what / action 是什么、默认是准还是拒、多条如何组合」,便会一目了然。
5 · 参考文献
- MDN. Same-origin policy. web 的 default-deny 地基,origin = scheme + host + port。developer.mozilla.org
- MDN. Cross-Origin Resource Sharing (CORS). 简单请求 / 预检 / 凭据,以及全部
Access-Control-Allow-*响应头。developer.mozilla.org - MDN. Content Security Policy (CSP). directive、source list、
default-src回退、report-only。developer.mozilla.org - MDN. Permissions-Policy header. 强能力的 allowlist 与 iframe 委派。developer.mozilla.org