反序列化调试 Proto 表示
从 30.x 版本开始,Protobuf DebugString
API(Message::DebugString
、Message::ShortDebugString
、Message::Utf8DebugString
)、额外的 Protobuf API(proto2::ShortFormat
、proto2::Utf8Format
)、Abseil 字符串函数(例如 absl::StrCat
、absl::StrFormat
、absl::StrAppend
和 absl::Substitute
)以及 Abseil 日志记录 API 将开始自动将 proto 参数转换为一种新的调试格式。请参阅此处的相关公告。
与 Protobuf DebugString 输出格式不同,新的调试格式通过将其值替换为字符串“[REDACTED]”(不含引号)来自动编辑敏感字段。此外,为了确保 Protobuf TextFormat 解析器无法反序列化这种新的输出格式,无论底层 proto 是否包含 SPII 字段,我们都会添加一组指向本文的随机链接和一段随机长度的空白序列。新的调试格式如下所示:
goo.gle/debugstr
spii_field: [REDACTED]
normal_field: "value"
请注意,新的调试格式与 DebugString 格式的输出格式仅在两方面有所不同:
- URL 前缀
- SPII 字段的值被替换为“[REDACTED]”(不含引号)
新的调试格式绝不会删除任何字段名称;它只会在字段被视为敏感时将其值替换为“[REDACTED]”。如果您在输出中没有看到某些字段,那是因为这些字段在 proto 中没有被设置。
提示: 如果您只看到 URL 而没有其他内容,说明您的 proto 是空的!
为什么这里会出现这个 URL?
我们希望确保没有人反序列化旨在供人类调试系统使用的 protobuf 消息的人类可读表示。历史上,.DebugString()
和 TextFormat
是可以互换的,现有系统使用 DebugString 来传输和存储数据。
我们希望确保敏感数据不会意外地出现在日志中。因此,我们在将 protobuf 消息转换为字符串之前,会透明地对一些字段值进行编辑(“[REDACTED]”)。这降低了意外日志记录带来的安全和隐私风险,但如果其他系统反序列化您的消息,则存在数据丢失的风险。为了解决这个风险,我们有意将机器可读的 TextFormat 与用于日志消息的人类可读的调试格式分开。
为什么我的网页里有链接?为什么我的代码会产生这种新的“调试表示”?
这是故意的,目的是让您的 protos 的“调试表示”(例如,由日志记录产生)与 TextFormat 不兼容。我们希望防止任何人依赖调试机制在程序之间传输数据。历史上,调试格式(由 DebugString API 生成)和 TextFormat 一直被错误地互换使用。我们希望这一有意的努力能防止这种情况在未来发生。
我们特意选择了一个链接,而不是不太明显的格式更改,以便有机会提供上下文。这可能会在 UI 中显得很突出,例如当您在网页的表格中显示状态信息时。您可以改用 TextFormat::PrintToString
,它不会编辑任何信息并保留格式。但是,请谨慎使用此 API——它没有任何内置保护。根据经验,如果您正在将数据写入调试日志或生成状态消息,您应该继续使用带有链接的调试格式。即使您目前没有处理敏感数据,也要记住系统会发生变化,代码会被重用。
我尝试将此消息转换为 TextFormat,但我注意到每次我的进程重启时格式都会改变。
这是故意的。不要尝试解析此调试格式的输出。我们保留在不通知的情况下更改语法的权利。调试格式的语法会随进程随机变化,以防止无意的依赖。如果调试格式的语法更改会破坏您的系统,那么您很可能应该使用 TextFormat API,而不是使用 proto 的调试表示。
常见问题解答
我可以直接在所有地方都使用 TextFormat 吗?
不要使用 TextFormat 来生成日志消息。这会绕过所有内置的保护措施,您将面临意外记录敏感信息的风险。即使您的系统目前没有处理任何敏感数据,这种情况在未来也可能改变。
通过酌情使用调试表示或 TextFormat,来区分日志和旨在供其他系统进一步处理的信息。
我想编写既需要人类可读又需要机器可读的配置文件
对于这种用例,您可以明确使用 TextFormat。您有责任确保您的配置文件不包含任何个人身份信息(PII)。
我正在编写单元测试,并希望在测试断言中比较调试字符串
如果您想比较 protobuf 的值,请使用 MessageDifferencer
,如下所示:
using google::protobuf::util::MessageDifferencer;
...
MessageDifferencer diff;
...
diff.Compare(foo, bar);
除了忽略格式和字段顺序的差异外,您还会得到更好的错误消息。