<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Web-Security · XB 现场笔记</title><link>https://hk.xbcatm.com/zh/tags/web-security/</link><description>基于 HTTP、DNS、TLS、Caddy、SSH、发布与恢复的可复现运维现场笔记。</description><generator>Hugo</generator><language>zh-CN</language><atom:link href="https://hk.xbcatm.com/zh/tags/web-security/index.xml" rel="self" type="application/rss+xml"/><item><title>安全响应头应描述实际页面</title><link>https://hk.xbcatm.com/zh/notes/security-headers-should-describe-the-actual-page/</link><pubDate>Thu, 23 Jul 2026 00:00:00 +0000</pubDate><guid>https://hk.xbcatm.com/zh/notes/security-headers-should-describe-the-actual-page/</guid><description>当紧凑的策略与静态页面真正加载的资源匹配时，它更安全。</description><content:encoded>&lt;p&gt;安全响应头不是安全代码的替代品，但它们让浏览器强制实施有用的边界。策略应描述实际被服务的页面，而不是从另一个项目复制来的泛型模板。&lt;/p&gt;
&lt;figure class="technical-diagram"&gt;&lt;img loading="lazy" src="https://hk.xbcatm.com/visuals/security-layers.detail.zh.svg" alt="HTML、本地样式表与 favicon 决定 CSP 资源许可。Content-Security-Policy 强制执行；Report-Only 揭示违规且报告需另行配置。CSP 应通过响应头发送：frame-ancestors 在 meta 中被忽略且不回退到 default-src，form-action 需要自己的指令，style-src self 本身不允许内联样式。HSTS 从有效 HTTPS 响应学习；www.example.test 的 includeSubDomains 覆盖该主机与后代，不覆盖 example.test 或 api.example.test。应检查正常页、缺失页与资源响应，并在真实浏览器验证执行。本图不声称已经测试。" width="720" height="3460"&gt;&lt;figcaption&gt;把响应头视为部署契约：匹配实际资源，区分强制执行与仅报告策略，再验证准确主机范围和浏览器行为。&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2 id="从资源图开始"&gt;从资源图开始&lt;/h2&gt;
&lt;p&gt;如果站点只提供 HTML、本地样式表、一个 favicon、没有任何可执行 JavaScript，那么一条窄策略是可理解的：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Content-Security-Policy: default-src &amp;#39;self&amp;#39;; base-uri &amp;#39;self&amp;#39;; form-action &amp;#39;none&amp;#39;; frame-ancestors &amp;#39;none&amp;#39;; object-src &amp;#39;none&amp;#39;; script-src &amp;#39;none&amp;#39;; style-src &amp;#39;self&amp;#39;; img-src &amp;#39;self&amp;#39; data:
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;script-src 'none'&lt;/code&gt; 只有在站点不需要可执行脚本时才是正确的选择。加入搜索、评论或统计标签会改变资源图，并应触发一次有意识的策略复核。&lt;/p&gt;
&lt;h2 id="增加传输与嵌套保护"&gt;增加传输与嵌套保护&lt;/h2&gt;
&lt;p&gt;对仅 HTTPS 的站点，下列响应头是常见起点：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Strict-Transport-Security: max-age=31536000; includeSubDomains
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;X-Content-Type-Options: nosniff
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;X-Frame-Options: DENY
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Referrer-Policy: strict-origin-when-cross-origin
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(), usb=()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;只有当每个子域名都准备好提供 HTTPS 时才启用带 includeSubDomains 的 HSTS。响应头是与未来部署的契约，而不只是扫描器里的一个分数。&lt;/p&gt;
&lt;h2 id="检查行为而不只是存在"&gt;检查行为，而不只是存在&lt;/h2&gt;
&lt;p&gt;请求一个正常页面、一个缺失页面与一个静态资源。错误响应应携带与成功响应同样重要的安全响应头。还要确认压缩与缓存不会改变内容类型，也不会暴露内部路径。&lt;/p&gt;
&lt;p&gt;本站的&lt;a href="https://hk.xbcatm.com/zh/resources/"&gt;Caddy 示例&lt;/a&gt;只是一个起点，不是普适策略。请根据你自己的部署调整主机名、证书处理与应用路由。&lt;/p&gt;
&lt;p&gt;通过响应头发送 CSP。meta 策略中的 &lt;code&gt;frame-ancestors&lt;/code&gt; 会被忽略，而且它不会继承 &lt;code&gt;default-src&lt;/code&gt;；&lt;code&gt;form-action&lt;/code&gt; 也需要自己的指令。&lt;code&gt;style-src 'self'&lt;/code&gt; 本身不允许内联样式，因此应测试生成的主题，包括深色模式。只有页面确实需要 data 图片时，才在 &lt;code&gt;img-src&lt;/code&gt; 中保留 &lt;code&gt;data:&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Content-Security-Policy-Report-Only&lt;/code&gt; 可在上线过程中揭示违规，但不会强制执行策略；报告端点还需单独配置。除了查看响应头，也要在真实浏览器中验证执行效果。HSTS 从有效 HTTPS 响应中学习；带有 &lt;code&gt;includeSubDomains&lt;/code&gt; 时，它还覆盖设置策略的主机的后代：&lt;code&gt;www.example.test&lt;/code&gt; 的策略不覆盖父域 &lt;code&gt;example.test&lt;/code&gt; 或同级 &lt;code&gt;api.example.test&lt;/code&gt;。确认这个准确范围后，再逐步延长有效期。&lt;/p&gt;
&lt;h2 id="来源"&gt;来源&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP"&gt;MDN: Content Security Policy guide&lt;/a&gt;，CSP 指令名称与语法，已核验 2026-07-23。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Strict-Transport-Security"&gt;MDN: &lt;code&gt;Strict-Transport-Security&lt;/code&gt;&lt;/a&gt;，HSTS 指令与部署注意事项，已核验 2026-07-23。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://caddyserver.com/docs/caddyfile/directives/header"&gt;Caddy &lt;code&gt;header&lt;/code&gt; 指令&lt;/a&gt;，响应头操作指令，已核验 2026-07-23。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.w3.org/TR/CSP3/"&gt;W3C Content Security Policy Level 3&lt;/a&gt;，响应头交付、指令回退、嵌套与仅报告策略；当前为工作草案，已核验 2026-10-15。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.rfc-editor.org/rfc/rfc6797.html"&gt;RFC 6797 — HTTP Strict Transport Security&lt;/a&gt;，第 8.1–8.3 节的有效 HTTPS 交付与主机及后代匹配，已核验 2026-10-15。&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>HSTS 应带着恢复计划来灰度发布</title><link>https://hk.xbcatm.com/zh/notes/hsts-should-be-rolled-out-with-a-recovery-plan/</link><pubDate>Tue, 23 Jun 2026 00:00:00 +0000</pubDate><guid>https://hk.xbcatm.com/zh/notes/hsts-should-be-rolled-out-with-a-recovery-plan/</guid><description>只有在 HTTPS、重定向与每个被子域名覆盖的域名都就绪之后，才增大 max-age。</description><content:encoded>&lt;p&gt;HTTP Strict Transport Security 告诉支持的浏览器，在一个缓存周期内对该主机强制使用 HTTPS。这种持久性既是特性也是风险：移除响应头并不会立刻抹掉客户端已存储的策略。&lt;/p&gt;
&lt;figure class="technical-diagram"&gt;&lt;img loading="lazy" src="https://hk.xbcatm.com/visuals/hsts-rollout.detail.zh.svg" alt="发布轨道要求检查 HTTPS 与重定向、采用短时长示例，并在观察站点与续期后选择时长。域名树将 includeSubDomains 限于发送主机的后代；独立的预加载和恢复面板说明已存策略的限制。" width="720" height="2530"&gt;&lt;figcaption&gt;观察后再增加 HSTS 时长，独立决定后代覆盖与预加载。恢复需要有效 HTTPS，也不能立刻抹除所有已存或预加载策略。&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2 id="先验证-https-路径"&gt;先验证 HTTPS 路径&lt;/h2&gt;
&lt;p&gt;在发送 HSTS 之前，确认规范主机名提供有效证书，并且 HTTP 在不依赖用户输入的情况下重定向到预期的 HTTPS URL：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -sS -D - -o /dev/null --max-redirs &lt;span class="m"&gt;0&lt;/span&gt; http://www.example.test/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -sS -D - -o /dev/null https://www.example.test/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;检查有代表性的深层路由与错误页。HSTS 无法修复证书错误，因为浏览器在接受该策略之前要求有效的 HTTPS 连接。&lt;/p&gt;
&lt;h2 id="从一个短的-max-age-开始"&gt;从一个短的 max-age 开始&lt;/h2&gt;
&lt;p&gt;分阶段发布能在配置还新的时候限制恢复窗口：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Strict-Transport-Security: max-age=300
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;观察站点与续期路径之后，再有意识地提高时长。记录日期、所选值与回滚条件。最终策略可能用一年，但这个数字是一种承诺，而不是扫描器分数。&lt;/p&gt;
&lt;h2 id="把-includesubdomains-当作独立的决定"&gt;把 includeSubDomains 当作独立的决定&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;includeSubDomains&lt;/code&gt; 把策略扩展到每个子域名。先盘点名称，包括旧服务、委派区，以及只在内部网络使用的主机名。即使只有一个仅 HTTP 的后代，也足以让该选项对收到父级策略的客户端产生破坏。&lt;/p&gt;
&lt;h2 id="预加载不是普通的响应头配置"&gt;预加载不是普通的响应头配置&lt;/h2&gt;
&lt;p&gt;浏览器预加载程序可以在正常响应周期之外分发策略，其要求与移除延迟比设置一个响应头更严格。不要仅仅因为扫描器推荐就申请预加载；请先确认对域名及所有被覆盖名称的长期所有权。&lt;/p&gt;
&lt;h2 id="验证公共响应"&gt;验证公共响应&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -sS -D - -o /dev/null https://www.example.test/ &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;|&lt;/span&gt; awk &lt;span class="s1"&gt;&amp;#39;tolower($1) == &amp;#34;strict-transport-security:&amp;#34; { print }&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;测试规范的公共边缘，而不只是某个源站端口。代理可能添加、移除或重复该响应头。&lt;/p&gt;
&lt;h2 id="知道回滚能清除什么"&gt;知道回滚能清除什么&lt;/h2&gt;
&lt;p&gt;通过有效 HTTPS 响应发送 &lt;code&gt;max-age=0&lt;/code&gt;，只会让收到该响应的客户端清除该主机已学习的策略。移除响应头或通过 HTTP 发送它，都不能清除已缓存策略。子域无法退出父域仍有效的 &lt;code&gt;includeSubDomains&lt;/code&gt;；清除父域策略，也不会删除客户端独立从子域学习到的策略。&lt;/p&gt;
&lt;p&gt;作用域由发送响应头的主机决定：&lt;code&gt;www.example.test&lt;/code&gt; 的策略覆盖自身，加上 &lt;code&gt;includeSubDomains&lt;/code&gt; 后覆盖其后代，但不覆盖同级的 &lt;code&gt;api.example.test&lt;/code&gt; 或父级 &lt;code&gt;example.test&lt;/code&gt;。恢复期间必须保持 HTTPS 可用。移除预加载是独立的浏览器更新过程，不是响应头的即时回滚。&lt;/p&gt;
&lt;h2 id="来源"&gt;来源&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.rfc-editor.org/rfc/rfc6797.html"&gt;RFC 6797 — HTTP Strict Transport Security&lt;/a&gt;，策略处理与作用域，已核验 2026-10-15。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Strict-Transport-Security"&gt;MDN: &lt;code&gt;Strict-Transport-Security&lt;/code&gt;&lt;/a&gt;，指令与部署注意事项，已核验 2026-10-15。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hstspreload.org/"&gt;HSTS 预加载项目&lt;/a&gt;，提交要求与移除限制，已核验 2026-10-15。&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>CAA 记录应授权你实际使用的签发者</title><link>https://hk.xbcatm.com/zh/notes/caa-records-should-authorize-the-issuer-you-actually-use/</link><pubDate>Wed, 17 Jun 2026 00:00:00 +0000</pubDate><guid>https://hk.xbcatm.com/zh/notes/caa-records-should-authorize-the-issuer-you-actually-use/</guid><description>在限制哪些证书签发机构能为一个域名签发之前，先检视继承的 CAA 策略。</description><content:encoded>&lt;p&gt;认证机构授权（CAA）记录让域名持有者声明，哪些证书颁发机构可以为该域名签发证书。只有当记录与真实续期路径一致、且操作者理解策略如何从父级名称继承时，它才有用。&lt;/p&gt;
&lt;figure class="technical-diagram"&gt;&lt;img loading="lazy" src="https://hk.xbcatm.com/visuals/caa-policy.detail.zh.svg" alt="跟随别名并逐级向上，遇到第一个相关非空 CAA 记录集就停止，不合并所有父级策略。使用 CA 的授权标识；issuewild 存在时优先控制通配符签发。CAA 约束签发，不执行 HTTPS 信任验证，也不吊销已有证书。应在当前证书健康时编排续期变更。" width="720" height="2164"&gt;&lt;figcaption&gt;CAA 在签发时授权签发者。查询遇到第一个相关非空记录集就停止，通配符标签进一步细化规则。已有证书与 HTTPS 信任属于不同边界，图中签发者仅为示例。&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2 id="检视当前策略"&gt;检视当前策略&lt;/h2&gt;
&lt;p&gt;查询确切主机名及其父名称：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; name in www.example.test example.test test&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;== %s\n&amp;#39;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; dig +noall +answer CAA &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里用占位域名通过已配置的解析器查询。叶子处空应答不一定代表没有适用策略：查询会跟随别名，并在逐级向上时遇到第一个相关的非空 CAA 记录集就停止，而不是合并所有父级限制。还要查看 DNS 状态与权威信息；只显示答案的空输出可能隐藏 &lt;code&gt;NXDOMAIN&lt;/code&gt; 或 &lt;code&gt;SERVFAIL&lt;/code&gt;。诊断变更时应比较权威应答与递归查询结果。&lt;/p&gt;
&lt;h2 id="匹配-ca-的签发者标识"&gt;匹配 CA 的签发者标识&lt;/h2&gt;
&lt;p&gt;记录使用如 &lt;code&gt;issue&lt;/code&gt; 或 &lt;code&gt;issuewild&lt;/code&gt; 等标签与一个签发者域值：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;example.test. 3600 IN CAA 0 issue &amp;#34;letsencrypt.org&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;该值是授权标识，不是证书里的显示名。在证书颁发机构的当前文档中确认它。没有 &lt;code&gt;issuewild&lt;/code&gt; 时，&lt;code&gt;issue&lt;/code&gt; 也控制通配符签发；存在 &lt;code&gt;issuewild&lt;/code&gt; 时，通配符请求优先适用它。同一标签的多条记录提供备选授权，并不是要求每一家 CA 同时参与。CAA 也不选择某张具体的中间证书。&lt;/p&gt;
&lt;h2 id="在续期前编排-dns-变更"&gt;在续期前编排 DNS 变更&lt;/h2&gt;
&lt;p&gt;在当前证书健康时添加或收紧 CAA。等待先前 TTL 对应的完整时间，查询权威与递归应答，并运行 ACME 客户端支持的暂存或续期测试。准备好回滚记录。&lt;/p&gt;
&lt;p&gt;不要在过期事故期间添加限制性记录，除非签发者路径已验证。一条语法正确但错误的策略，会把自动续期变成硬失败。&lt;/p&gt;
&lt;h2 id="观察签发失败"&gt;观察签发失败&lt;/h2&gt;
&lt;p&gt;CAA 检查发生在签发时，而不是每次 HTTPS 请求。修改 CAA 不会吊销已有证书，也不能证明历史签发符合当时的策略。因此证书监控必须同时覆盖当前过期与续期尝试。把有效的 DNS 应答随 ACME 失败一起记录，而不是只记录一条笼统的授权错误。&lt;/p&gt;
&lt;h2 id="来源"&gt;来源&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.rfc-editor.org/rfc/rfc8659.html"&gt;RFC 8659 — DNS Certification Authority Authorization&lt;/a&gt;，CAA 查询与属性语义，已核验 2026-10-15。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://letsencrypt.org/docs/caa/"&gt;Let&amp;rsquo;s Encrypt: CAA&lt;/a&gt;，签发者标识与运维指引，已核验 2026-10-15。&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>Cookie 作用域应比应用边界更窄</title><link>https://hk.xbcatm.com/zh/notes/cookie-scope-should-be-narrower-than-the-application-boundary/</link><pubDate>Mon, 15 Jun 2026 00:00:00 +0000</pubDate><guid>https://hk.xbcatm.com/zh/notes/cookie-scope-should-be-narrower-than-the-application-boundary/</guid><description>把 Domain、Path、Secure、HttpOnly 与 SameSite 当作同一份浏览器存储契约来复核。</description><content:encoded>&lt;p&gt;Cookie 依据浏览器规则附加到请求，而不是依据最初设置它的服务器组件。宽泛的 &lt;code&gt;Domain&lt;/code&gt; 或 &lt;code&gt;Path&lt;/code&gt; 会把状态暴露给无关的路由或子域名，而缺失传输与脚本限制则会放大其他失败造成的损害。&lt;/p&gt;
&lt;figure class="technical-diagram"&gt;&lt;img loading="lazy" src="https://hk.xbcatm.com/visuals/cookie-scope.detail.zh.svg" alt="先区分仅主机与 Domain 作用域。Path 选择请求路径，不构成授权边界。Secure 限制传输，但不加密存储。SameSite 影响跨站上下文，现代浏览器的 None 还需要 Secure。HttpOnly 阻止 document.cookie 访问，但浏览器仍发送 Cookie。支持前缀的浏览器要求 __Host- 使用 Secure、无 Domain 且 Path=/。删除匹配名称和域名/路径作用域，并满足前缀和安全来源要求；服务器会话失效另行处理。静态站点应同时检查响应头与浏览器存储。" width="720" height="3300"&gt;&lt;figcaption&gt;一起复核这些维度，同时区分发送目的地、JavaScript 访问权限与删除所针对的存储身份。&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2 id="偏好仅主机-cookie"&gt;偏好仅主机 Cookie&lt;/h2&gt;
&lt;p&gt;当省略 &lt;code&gt;Domain&lt;/code&gt; 时，Cookie 被限定在设置它的主机内。加上 &lt;code&gt;Domain=example.test&lt;/code&gt; 则它也允许发给符合条件子域名。只有多个主机确实共享同一应用与信任边界时才使用更宽的形式。&lt;/p&gt;
&lt;p&gt;检视响应而不把真实 Cookie 值打进日志。头部名称不区分大小写，脱敏也必须覆盖 HTTP/2 风格的小写名称：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -sS -D - -o /dev/null https://app.example.test/login &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;|&lt;/span&gt; awk &lt;span class="s1"&gt;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; tolower($0) ~ /^set-cookie:/ {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; sub(/^[^:]*:[^;]*/, &amp;#34;Set-Cookie: [value redacted]&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; print
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="一起复核这些属性"&gt;一起复核这些属性&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Secure&lt;/code&gt; 把 Cookie 传输限制在安全传输上，通常是 HTTPS；它不会加密存储的值。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HttpOnly&lt;/code&gt; 通过 &lt;code&gt;document.cookie&lt;/code&gt; 阻止 JavaScript 访问；它不会阻止浏览器发送该 Cookie。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SameSite&lt;/code&gt; 影响跨站请求，必须匹配应用的导航或嵌入需求。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Path&lt;/code&gt; 控制发送时机，但它不是同一主机上不同应用之间的授权边界。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在现代浏览器中，&lt;code&gt;SameSite=None&lt;/code&gt; 的 Cookie 还需要 &lt;code&gt;Secure&lt;/code&gt;。避免把这对组合复制进不需要跨站用途的应用。&lt;/p&gt;
&lt;p&gt;同站比同源更宽：使用 HTTPS 的兄弟子域名可以同站，同时仍属于不同源。因此，&lt;code&gt;SameSite&lt;/code&gt; 不能替代主机边界或应用自身的 CSRF 防护。Cookie 也不按端口隔离，即便使用 &lt;code&gt;__Host-&lt;/code&gt; 前缀也是如此。&lt;/p&gt;
&lt;h2 id="在其约束契合时使用前缀"&gt;在其约束契合时使用前缀&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;__Secure-&lt;/code&gt; 与 &lt;code&gt;__Host-&lt;/code&gt; 等 Cookie 名称前缀，让支持的浏览器强制额外的要求。&lt;code&gt;__Host-&lt;/code&gt; Cookie 必须使用 &lt;code&gt;Secure&lt;/code&gt;、省略 &lt;code&gt;Domain&lt;/code&gt;、并使用 &lt;code&gt;Path=/&lt;/code&gt;，这使主机专用的意图变得显式。&lt;/p&gt;
&lt;h2 id="用相同作用域测试删除"&gt;用相同作用域测试删除&lt;/h2&gt;
&lt;p&gt;使用 &lt;code&gt;Max-Age=0&lt;/code&gt; 或过去的 &lt;code&gt;Expires&lt;/code&gt; 值，删除同名且域名/路径作用域相同的 Cookie；并非每个属性都参与存储身份。发送删除指令仍需满足前缀与安全来源要求。应保留最初是否省略 &lt;code&gt;Domain&lt;/code&gt; 的选择：让仅主机 Cookie 过期时不要添加 &lt;code&gt;Domain&lt;/code&gt;，并明确指定原来的 &lt;code&gt;Path&lt;/code&gt;。当前 6265bis 草案把仅主机标记也纳入存储身份，因此只匹配界面显示的域名字符串，不足以构成可移植的删除方法。应在目标浏览器中验证删除结果。登出只清除一个作用域时，另一个可能仍然有效；服务器端会话或令牌也可能需要失效处理。&lt;/p&gt;
&lt;h2 id="让静态站点免-cookie"&gt;让静态站点免 Cookie&lt;/h2&gt;
&lt;p&gt;一个真正静态的文档站点通常没有理由设置应用 Cookie。检查有代表性的公共响应是否包含 &lt;code&gt;Set-Cookie&lt;/code&gt;，并在导航后检视浏览器存储，包含第三方脚本的影响。单靠 curl 响应头检查发现不了 JavaScript 设置的 Cookie 或其他浏览器存储；避免增加站点并不需要的存储。&lt;/p&gt;
&lt;h2 id="来源"&gt;来源&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.rfc-editor.org/rfc/rfc6265.html"&gt;RFC 6265 — HTTP State Management Mechanism&lt;/a&gt;，Cookie 存储与作用域，已核验 2026-10-15。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Set-Cookie"&gt;MDN: &lt;code&gt;Set-Cookie&lt;/code&gt;&lt;/a&gt;，属性与名称前缀，已核验 2026-10-15。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://httpwg.org/http-extensions/draft-ietf-httpbis-rfc6265bis.html"&gt;HTTPWG Cookie 规范草案&lt;/a&gt;，SameSite 与 Cookie 前缀要求，已核验 2026-10-15。&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>Content-Type 应描述你实际发送的字节</title><link>https://hk.xbcatm.com/zh/notes/content-type-should-describe-the-bytes-you-actually-send/</link><pubDate>Thu, 11 Jun 2026 00:00:00 +0000</pubDate><guid>https://hk.xbcatm.com/zh/notes/content-type-should-describe-the-bytes-you-actually-send/</guid><description>在公开边缘核对媒体类型，并用 nosniff 让不匹配以可见的方式失败。</description><content:encoded>&lt;p&gt;静态服务器可能返回正确的字节，却带上错误的 &lt;code&gt;Content-Type&lt;/code&gt;。某个浏览器里页面看起来或许还正常，但下载、样式表、订阅阅读器或安全策略会把同一响应理解成别的东西。公开响应头才是契约；文件名只是服务器配置的输入。&lt;/p&gt;
&lt;figure class="technical-diagram"&gt;&lt;img loading="lazy" src="https://hk.xbcatm.com/visuals/content-type.detail.zh.svg" alt="CSS 路径之后检查公开响应的状态、实际字节和 Content-Type。正确 CSS 与 HTML 错误页分列。浏览器脚本和样式目标使用 nosniff，失败时应修复响应；CDN 或代理的公开响应头需要单独核对。" width="720" height="2080"&gt;&lt;figcaption&gt;后缀不能证明实际收到的内容。应同时检查公开响应的状态、字节与媒体类型；CSS 路径上的 HTML 错误页不能用来测试 MIME 映射。nosniff 让脚本和样式目标上的类型不匹配以可见方式失败。&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2 id="检查有代表性的格式"&gt;检查有代表性的格式&lt;/h2&gt;
&lt;p&gt;检查一份 HTML 文档、样式表、SVG、feed 与可下载脚本。包含响应头但丢弃正文：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; path in / /assets/site.css /favicon.svg /index.xml /downloads/check-http-headers.sh&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; curl -sS -D - -o /dev/null &lt;span class="s2"&gt;&amp;#34;https://www.example.test&lt;/span&gt;&lt;span class="nv"&gt;$path&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;|&lt;/span&gt; awk -v &lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$path&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; BEGIN { print &amp;#34;== &amp;#34; path }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; /^HTTP\// || tolower($1) == &amp;#34;content-type:&amp;#34; || tolower($1) == &amp;#34;x-content-type-options:&amp;#34; { print }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;把示例资源路径换成当前发布中确实存在的文件；虚构 CSS 路径返回 HTML 404，并不能测试 MIME 映射。期望的媒体类型因资源而异，但应该具体且稳定。HTML 通常应包含字符集。CSS 与 SVG 不应被当作泛型二进制数据提供服务。用于下载的 shell 脚本不应被声明为 HTML。&lt;/p&gt;
&lt;p&gt;该循环只是展示响应头，不会自动断言成功、检视被丢弃的字节，也不会执行浏览器的阻止逻辑。应将资源与发布制品核对，并在浏览器中检查它作为样式表或脚本的实际加载结果。把相同 URL 直接当作文档打开，测试的是另一种请求目标。&lt;/p&gt;
&lt;h2 id="保持-nosniff-一致"&gt;保持 nosniff 一致&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;X-Content-Type-Options: nosniff&lt;/code&gt; 请求支持它的浏览器在脚本与样式目标上尊重声明的类型，而不是猜测。在这项 Fetch 检查中，脚本类目标需要 JavaScript MIME 类型，样式目标需要 &lt;code&gt;text/css&lt;/code&gt;；类型缺失或无法使用也会失败。这样，不匹配会变成可见的失败，而不是因浏览器而异的解读。&lt;/p&gt;
&lt;p&gt;该响应头不能修复错误类型，也不能让任意内容变安全。部署时核对资源清单；若脚本或样式被拒绝，应修复响应，而不是移除保护：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;X-Content-Type-Options: nosniff
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="检查服务器映射"&gt;检查服务器映射&lt;/h2&gt;
&lt;p&gt;静态服务器通常根据扩展名推导类型。如果某个新扩展名被当作 &lt;code&gt;application/octet-stream&lt;/code&gt; 提供服务，先判断这是否有意为之，再决定是否加入全局覆盖。一个窄映射比一条会改变所有响应的规则更容易复核。&lt;/p&gt;
&lt;p&gt;在公开主机名上重复这些检查。CDN 或反向代理可能替换掉正确的源站响应头；而一个友好的错误页可能为后缀像 CSS 或 JavaScript 的路径返回 HTML。&lt;/p&gt;
&lt;h2 id="来源"&gt;来源&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.rfc-editor.org/rfc/rfc9110.html"&gt;RFC 9110 — HTTP Semantics&lt;/a&gt;，表示元数据与 &lt;code&gt;Content-Type&lt;/code&gt;，已核验 2026-10-15。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Type"&gt;MDN: &lt;code&gt;Content-Type&lt;/code&gt;&lt;/a&gt;，媒体类型与字符集示例，已核验 2026-10-15。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Content-Type-Options"&gt;MDN: &lt;code&gt;X-Content-Type-Options&lt;/code&gt;&lt;/a&gt;，&lt;code&gt;nosniff&lt;/code&gt; 行为，已核验 2026-10-15。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fetch.spec.whatwg.org/#should-response-to-request-be-blocked-due-to-nosniff"&gt;WHATWG Fetch 标准&lt;/a&gt;，脚本类与样式目标的阻止规则，已核验 2026-10-15。&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item></channel></rss>