HTTP 中的 policy:浏览器是一台 PDP
打开浏览器的 Network 面板,你会看到许多带 Policy 字样的响应头:Content-Security-Policy、
Permissions-Policy、Cross-Origin-*-Policy……它们并非杂乱无章的开关,而是同一件事的不同侧面:
服务器声明策略 (PAP),浏览器当场判 permit / deny (PDP) 并执行 (PEP)。而且它们大多能精确解码回 01-request 的那个四元组 ——
只不过这里的 principal (who) 是 origin:scheme + host + port。
*-Policy 头,
要么是放宽这条默认拒绝 (CORS),要么是在它之上再收紧 (CSP / Permissions-Policy)。
它们和 05-decide 的结论一脉相承:先定默认决策 (deny),再用显式规则增删。
CORS:服务器声明「谁能跨域读我」
跨域请求里,who = 请求方 Origin、action = HTTP method、what = 目标资源。
服务器用一组 Access-Control-Allow-* 响应头声明它的放行策略,判定却发生在浏览器端。
下面固定服务器 https://api.example,你调整请求与服务器策略,观察浏览器如何判定:
● 请求 (浏览器侧:谁 / 什么动作)
服务器策略 (api.example 的响应头:PAP)
简单请求 (GET / HEAD / 简单 POST) 没有预检 —— 浏览器照样把请求发给服务器, 只是当 CORS 不通过时拦截 JS 读响应。也就是说副作用可能已经发生,CORS 不是服务器侧的访问控制, 真正的鉴权仍要服务器自己做 (即 05-decide 的判定函数)。
非简单请求 (PUT/DELETE、自定义头、JSON body) 先发
OPTIONS 预检;
预检不过,真正的请求根本不发。
凭据请求 (
credentials) 下,Allow-Origin: * 无效 —— 必须回显具体 origin。
CSP:文档声明「谁能往我身上加资源」
Content-Security-Policy 换了个轴:who = 子资源的来源 (origin / nonce / hash)、
what = 资源类型 (由 directive 表示:script-src / img-src / connect-src……)、
action = load / execute。它是一份白名单策略,未声明的 directive 回退到 default-src。
下面编写一份 CSP,再用一个资源去匹配,观察哪条 directive 命中、放行还是拦截:
CSP 策略 (每条 directive 选若干来源;不选 = 该 directive 缺省)
要加载的资源 (who / what / action)
directive 匹配 (亮 = 适用于本次加载;高亮 = 命中的那条)
缺省回退:
script-src 没写就用 default-src;default-src 也没写,
这类资源就不受限 (allow)。用 connect 类资源 (fetch) 试一下 —— 本页未提供 connect-src,它会回退到 default-src。
多份 CSP = deny-overrides:一个响应可带多份 CSP (头 + meta、或多个头),浏览器取交集 —— 每一份都必须放行才放行。这正是 05-decide 的
deny-overrides。
Report-Only = dry-run:
Content-Security-Policy-Report-Only 不拦截、只上报违规 ——
等于 05-decide 里「permit 但附带 obligation:上报」的 审计 / 演练模式。
同一个模式的其它头
识别出「谁 (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 = 强制升级 / 拒。
一张表收束: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 关系判定 |
*-Policy,
先问「它的 who / what / action 是什么、默认是准还是拒、多条如何组合」,便会一目了然。
相关链接
- MDN · Same-origin policydeveloper.mozilla.orgweb 的 default-deny 地基,origin = scheme+host+port。
- MDN · CORSdeveloper.mozilla.org简单请求 / 预检 / 凭据,以及全部 Access-Control-Allow-* 响应头。
- MDN · Content Security Policydeveloper.mozilla.orgdirective、source list、default-src 回退、report-only。
- MDN · Permissions-Policydeveloper.mozilla.org强能力的 allowlist 与 iframe 委派。
- 回看:决策与组合算法 (default-deny / deny-overrides / obligation)@vega/playground本页所有「默认 / 组合 / 上报」都对应这里的概念。