正确传递的baggage也不是权限证明
一句话总结
baggage 传播的功能是搬运信息。本实验读取外部值时不与本地请求混合,并且只向指定目的地发送指定键和值。能读取一个值,不等于通过认证、授权,也不保证个人信息安全。
为什么需要它
假设发往库存服务的订单请求带有 region 和 channel,运维人员想按地区与来源划分慢区间。但有人在同一 baggage 中加入 role=admin 或邮箱形式的值。把全部内容注入另一台服务器,语法虽然正确,却会让不必要信息跨越边界。
更危险的误解,是看到 role=admin 就判断这是管理员请求。本模块输入是任何人都能构造的合成 header。读取值的函数与验证用户权限的系统完全不同,实验甚至没有认证服务器。不能以 header 成功传播为证据,宣称权限验证成功。
OpenTelemetry 文档说明 baggage 不内置完整性校验,并提醒注意传播信息的暴露;baggage 也不会自动成为 span 属性。官方 Baggage 说明。本模块用小型输入输出函数的反例验证这些警告。
工作原理
传入的 Context 与原先附加的 Context
预实验先给调用方附加 request=alpha,再提取外部 baggage。默认提取结果同时保留外部值与已有本地 request;明确以空 OpenTelemetry Context 提取时,只留下外部值。起初预计两者相同,实际执行证明错误,因此把差异设计成任务。
| 本实验的提取条件 | 观测到的 baggage |
|---|---|
| 当前有本地 request 时默认提取 | 同时包含本地 request 与外部值 |
| 指定空 Context 提取 | 只有外部值 |
| 空 Context 加空 header | 空 baggage |
第 6 步 inbound 是在独立上下文中读取外部 header 的函数。它不得改变输入 dict 或调用方当前状态,必须返回新的 OTel Context。外部 role=admin 在此阶段仍保留在读取结果中;这不表示应信任或使用它,而是为了分别观测“提取”和“按策略选择”。
这里的空 Context 是 OpenTelemetry Context。它与前面 executor 使用的 contextvars.Context 名称相似,却不是返回契约相同的对象。应确认各函数要求返回什么类型;类型错误时,即使值偶然相同,也无法正确连接后续传播 API。
从空上下文读取可防止与现有请求混合,却无法判断外部值真伪。必须明确这一限制,避免产生“新 Context 就安全”的另一条万能规则。业务权限应由独立、已验证的身份与策略决定。
只允许键是否足够
第 7 步修复 outbound(source, destination)。只允许名为 region 的键,不表示其中任何字符串都可以发送。若有人把长说明或标识符放进 region,键名虽在允许列表中,内容却不属于任务分类体系,因此本任务连值集合也封闭。
| 条件 | 本任务允许的内容 |
|---|---|
| 目的地字符串 | 必须恰好等于 warehouse.internal |
| region 值 | test-east 或 test-west |
| channel 值 | web 或 batch |
| 其他键、值或目的地 | 不传播 |
这些名称和值是合成分类,不是真实生产信息。允许值是有限的短字符串,所以本任务也排除任意长度字符串。但不能把它称作适合所有服务的通用隐私政策;真实策略要结合用途、接收者、保留期和访问主体制定。本实验只验证函数是否准确遵守表中规则。
大小写和空格也不自动修正。WEB 或 test-east 后带空格,都不是契约允许值。应规范化还是拒绝,是接口设计选择;本任务明确选择只传递允许字符串,而非静默规范化。
目的地边界不是字符串前缀
warehouse.internal.evil 虽以 warehouse.internal 开头,却不是同一目的地。实验会把该反例传给真实函数。若用 startswith 放行,即使地区过滤正确,也会在目的地策略失败。其他目的地必须返回空 dict;即使目的地允许,过滤后无剩余值,也不应生成空 baggage header。
这里有重要范围限制:destination 是逻辑目的地标识符。实验不会做 DNS 查询、URL 解析、TLS 证书验证或 HTTP 重定向。因此,字符串比较通过并不表示真实 HTTP 客户端的目的地验证或 SSRF 防护已经完成。存在网络连接的系统必须另行设计和测试该边界。
不删除原文,而是创建要发送的上下文
学员函数从 source 中选择必要值,写入新 Context,再用 W3C propagator 生成 header。原文中 role 等值不需要发送,并不表示任务要修改原文;原文可能还供其他策略使用,因此函数契约要求保留。评分器会重新提取传播结果比较,也会对照原文前后。
header 字符串顺序无需与答案完全一致。语义相同的 W3C baggage 不会因键顺序被拒绝;但禁止键若通过其他 header 名泄漏,则会失败。返回 dict 只允许一个 baggage 字符串 header 或空 dict,避免评分“对顺序严格、对泄漏宽松”。
baggage 与 span 属性是不同观测
预实验在附加 baggage 后结束真实 SDK span,再从 exporter 读取。baggage 没有自动出现在 span 属性中。第 8 步报告中的相应假设,应根据该观测和官方说明判断。当前实验第 1~7 步验证 Context 函数,不会每步都创建 span 或存入 Collector。
区分传播信息与记录到 span 的信息,也会让调查计划更清晰:哪些键作为 header 发出、是否进入接收 Context、是否被选择性写入 span 属性、是否留在存储中,都是不同问题。不要因为在一处看到值,就报告其余边界也已确认。
现场会遇到的情况
以此做代码评审时,不能只看一个正常 header,还要对照空 header、未知键、已知键的非法值、其他目的地、看似允许主机的前缀,以及原请求已有本地值的情况。无需真实数据也能为每个边界构造反例。先用合成数据重现失败条件,可在不收集无关生产信息的前提下缩小代码职责。
下一实验要做什么
第 6 步把传入值与现有请求分开读取。第 7 步按表中的目的地、键和值策略创建待发送 header。第 8 步判断关于传播时点、恢复和信任范围的八个假设。这不是只写对报告就能通过的任务;前七个函数行为必须全部正确,综合验证才会通过,而且不能把通过范围扩大成外部认证或整体网络安全。