TLS 保护一段查询路径,所选解析器仍会收到明文 DNS 问题。

DoT 与 DoH 保护通往已认证解析器的连接

DNS over TLS 和 DNS over HTTPS 保护其端点之间加密连接上的 DNS 流量。对于典型客户端,这条连接终止于选定解析器;解析器能够读取问题与回答,它随后发出的查询还可能使用不同传输。加密这一跳,不会自动加密整个递归过程,也不会让解析器失去记录所处理名称的能力。隐私范围应按真实连接边界说明,而不是笼统称为整个 DNS 都已保密。 坏掉的样子 加密套接字如果没有按预期验证证书,也可能连接到错误端点。应同时验证证书信任链和客户端期望的解析器身份;握手成功本身不能证明这两项检查已启用。失败时悄悄改用其他解析器或明文路径的配置,也会改变隐私契约。需要通过真实调用方了解这些行为,不能只看到配置文件中有一个 TLS 或 HTTPS 地址,就认定所有查询都符合预期。 DoH 使用 HTTPS,但四百四十三端口不会让它在所有网络中都无法识别、无法阻止或完全等同于任意网页流量。目的地址、连接时间和其他元信息仍可观察,TLS 终止点还可以检查明文 HTTP。选择解析器和传输策略时,应考虑这些边界,不能假定 HTTPS URL 会消除所有与 DNS 活动有关的信息暴露,也不能由加密推导解析器不会保存日志。 两种协议的消息边界也不同。DoT 通常使用八百五十三端口,在 TLS 内携带具有两字节 TCP 长度前缀的 DNS 消息。DoH 通常使用四百四十三端口上的 HTTPS 端点。标准 DoH 使用 application/dns-message 传递 DNS 线格式:POST 放在正文,GET 使用经 base64url 编码的 dns 参数。它不是任意 JSON 接口只要套上 HTTPS 就符合标准。 ...

十月 7, 2027 · 3 分钟 · XB Field Notes
两个事务按一种顺序取得编号,却按另一种顺序提交。

顺序标识会透露分配规律

顺序标识让相邻的值很容易被猜到。看到第四千号订单,观察者就知道可以从附近的编号继续探测;持续收集编号,也可能看出分配活动的大致变化。但这不代表系统恰好有四千张订单,不代表每个编号都对应成功购买,也不代表最大编号最后提交。想得出这些结论,还需要序列本身没有记录的业务事实。 坏掉的样子 PostgreSQL 序列取值不会跟随普通事务回滚而退回。一次最终放弃的插入,也可能永久消耗一个号码。删除记录、缓存预留区间、显式修改序列以及多个并发写者,都会进一步拉开计数器与当前行数的距离。因此,用最大编号充当客户数或销售数量,即使没有攻击者参与,也会生成错误的经营报表。号码可以提供线索,却不能直接当作精确统计结果。 分配顺序同样不等于提交顺序。事务甲可能先取得较小编号,随后停在那里;事务乙取得较大编号后,反而先完成提交。如果消费者把递增主键当作完整的已提交事件流,就可能先处理较大的行并推进位置,而较小的行此时还不可见。等它后来提交,消费者已经越过了它。数字主键不能直接替代变更捕获位置,也不能证明所有业务事件的先后关系。 随机标识让逐个递增枚举变得困难,却不会自动实施访问控制。UUID 仍可能出现在日志、分享链接或其他接口返回值里,拿到它的人仍须通过对象权限检查。第四版 UUID 使用随机位;第七版在开头放置毫秒时间戳,目标之一是支持时间排序,因此不能把它的前缀说成随机位,也不能把其中的时间当作数据库提交时间。降低可猜测性与确认谁有权读取,是两项不同职责。 快速验证 准备一个可丢弃的 PostgreSQL 18 数据库,打开两个管理员 psql 会话,分别称为甲和乙。下文提取 UUID 信息的函数要求此版本。确认实验模式名和两个角色名尚未使用,初始保持自动提交,隔离级别采用通常的读已提交。先在乙中建立数据: CREATE SCHEMA article_ids; CREATE ROLE article_id_alice NOLOGIN; CREATE ROLE article_id_bob NOLOGIN; SET search_path=article_ids,public; CREATE TABLE objects ( id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, public_id uuid NOT NULL DEFAULT gen_random_uuid() UNIQUE, owner text NOT NULL, label text NOT NULL ); 在甲中取出第一个编号,但暂时不要提交: ...

五月 29, 2027 · 2 分钟 · XB Field Notes
三个相连的方块,依次标注观察、决策与行动。

Referrer-Policy 决定发送多少来源地址信息

HTTP 的 Referer 请求头可以告诉接收方,这次请求由哪个页面发起。它保留了历史拼写,与控制来源信息范围的 Referrer-Policy 并不完全同名。根据策略和目标地址,值可能包含源页面的路径与查询参数,也可能只剩来源部分,或者完全省略。现代浏览器的默认行为并不是向每一个外部目标发送完整地址,不能沿用这种错误前提解释所有来源信息泄露。 当前通常采用的默认策略是严格的跨源仅来源策略:同源请求可以发送路径和查询信息,安全级别合适的跨源请求只发送来源,遇到从 HTTPS 到 HTTP 等安全降级则不发送引用来源。主动设置策略,仍有助于让团队审阅明确的预期行为。只暴露来源虽然少于完整地址,但主机名称本身仍然可能带有业务含义,不能未经判断就把来源级信息一概称为无敏感性的统计数据。 区分几种策略的具体选择 不发送引用来源的策略会省略整个请求头,同源策略只对同源目标保留较完整的值,而不安全地址策略会更广泛地披露来源、路径和查询参数,包括一些严格策略本来会抑制的场景。地址片段会从引用来源计算中移除,因此地址栏里的片段不应出现在接收方的 Referer 中。但这并不表示片段对页面脚本或浏览器状态保密,它只是没有通过这个请求头传送。 文档策略可以通过响应头设置,在合适场景下也可以使用名称为 referrer 的 HTML meta 元素。不能把自造的 http-equiv=“Referrer-Policy” 标签当成同等语法。部分元素以及 fetch 请求还支持单次请求自己的引用来源策略,因此单看文档响应头不一定能解释每一个实际请求。观察到不同结果时,应检查请求由什么上下文发起,以及它是否明确指定了自己的策略。 坏掉的样子 应用如果依赖收到完整 Referer 路径,可能在策略收紧或浏览器隐私行为减少信息后突然失效。引用来源并不是可靠的认证凭据,也不能代替明确的应用参数。同样,修改这项策略不会授予读取跨源响应的 CORS 权限,也不会删除已经写入目标地址的访问令牌。它只控制请求中的一种元数据,不能被当成同时处理全部信息流动的开关。 另一个错误是把跨源与跨站混为一谈。同一主机上的不同端口已经属于不同来源,足以改变本例的策略结果。同源请求也仍然可能把敏感路径或查询信息交给该来源上的另一个接口。需要核对每个接收者实际需要什么;当观察到的值与文档看起来采用的默认值不一致时,还要检查重定向链及资源自己的策略,不能只依据域名相似就认定浏览器表现异常。 快速验证 保存脚本为 referrer-policy.py,执行 python3 referrer-policy.py –serve。在打印出的页面地址后追加 ?policy=strict-origin-when-cross-origin&demo=visible#fragment-not-sent 并打开。本次使用 Python 3.14.4 与 Chrome 152,两个临时回环服务分别提供页面和跨源接收端。页面实际请求同源接口与跨源接口,由接口返回自己收到的 Referer 值,结束后按控制键加 C 关闭两个服务。 ...

三月 24, 2027 · 2 分钟 · XB Field Notes
一条标记 private 只留给用户浏览器,另一条标记 public 任何缓存都能用。

Cache-Control:private 还是 shared

存储范围不是身份系统。Cache-Control: private 要求遵守协议的共享缓存不存储这条响应,却不会教会浏览器识别正文属于哪个应用账户。当一个人退出登录,另一个账户在同一浏览器中登录,然后访问相同网址时,这个区别就会变成实际的数据隔离问题,不能只凭响应头里出现 private 就判定安全。 有资格被缓存不代表能共享 不带字段名参数的 private 允许单用户缓存保存响应,但仍受其他缓存条件约束。浏览器是常见实现,并不是唯一实现。public 则明确允许某些原本可能受到限制的响应进入缓存,例如满足条件的带授权请求响应。已经符合缓存条件的普通响应不一定需要 public;出现 public 也不意味着所有缓存都必须保存它,存储许可和实际是否存储是不同事实。 不带参数的 no-cache 与 no-store 回答的是另一个问题。前者允许存储,但每次复用前必须成功验证;后者禁止私有和共享 HTTP 缓存存储及随后复用该响应。它们都不是加密、访问控制检查,也不承诺清除应用日志或用户之前保存的副本。本文讨论不带字段名参数的形式,不把实现支持较弱的按字段限定形式混进实验。 新鲜度还需要单独判断。错误的个人响应如果按共享键保存,即使只给五秒钟有效期,也可能有五秒钟把数据交给另一个人。缩短 max-age 不能修复身份边界。反过来,s-maxage 只是控制共享缓存的新鲜度,并不是 private 的另一种写法。先决定响应可在哪一层保存,再讨论可直接复用多久,才能避免用性能参数代替安全条件。 坏掉的样子 HTTP 的通用规则不会因为请求里有 Cookie 就自动禁止共享缓存。Authorization 确实有专门的共享缓存限制,但 public 等指令能够明确允许存储。为了提高命中率而添加 public,可能恰好撤掉应用之前依赖的限制。修改指令前应检查实际响应体和认证路径,不能只查看页面看起来是不是一份普通文档。 Vary 细化的是请求匹配条件,不授予存储许可。增加 Vary: Cookie 不会让 private 响应变得可以进入共享缓存。在私有缓存内,它可以区分不同 Cookie 字段,但这仍然只是字段匹配,不是授权判断。假设令牌文本没有变化,而账户权限已经被撤销,仅凭请求字段仍匹配,不能证明当前用户继续有权读取旧内容。 ...

十月 23, 2026 · 2 分钟 · XB Field Notes