标头即数据包
HTTP 日志框架将请求标头视为一组键值对。日志 API 会暴露整个数据包。运维人员为了调试会开启标头日志记录:当请求失败时,标头能还原完整过程。框架没有内置黑名单,也没有在文档中提供凭证过滤机制。完整标头会被写入磁盘。
典型请求中的凭证标头:
- Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...(JWT 或 OAuth 令牌)
- Cookie: session=abc123; auth=xyz789
- X-API-Key: sk-live-abc123...
- X-Auth-Token: ghp_abc123...(GitHub 个人访问令牌格式)
这些值用于对请求进行身份验证。一旦写入日志文件,它们就可以对任何请求进行身份验证。
凭证传输链
写入日志文件的凭证不会停留在原地。它会继续流动:
1. Web 服务器写入 /var/log/nginx/access.log
2. 日志轮转工具(logrotate)复制到 /var/log/nginx/access.log.1
3. 日志收集器(Fluentd、Filebeat、Logstash)读取并发送到聚合器
4. 日志聚合器(Elasticsearch、Splunk、Datadog)建立索引并存储
5. 默认策略下保留 30-90 天
该凭证同时存在于全部五个位置。吊销会话令牌不会从日志聚合器中移除凭证。在整个保留期内,任何拥有日志访问权限的人都可以搜索、导出并访问该凭证。
暴露窗口
内存中凭证的暴露窗口:max(会话持续时间, 进程生命周期)。会话:数小时至数天。进程:数小时至数周。
日志中凭证的暴露窗口:max(会话持续时间, 日志保留期)。会话:数小时至数天。保留期:30-90 天。
从内存中窃取凭证需要攻击者在会话窗口期内在线。从日志中窃取凭证只需访问日志聚合器,且可在保留期内追溯获取。
MOAD-0003 vs MOAD-0004
MOAD-0003(内存泄露):凭据在内存中泄露给错误的请求处理器。仅在进程窗口期间,通过线程池可访问。临时性。
MOAD-0004(日志中的密钥):凭据在磁盘上,通过日志轮转、日志传输和日志聚合持续存在。任何拥有日志访问权限的人都可追溯访问,持续 30-90 天。持久性。
结构差异:临时 vs 持久。修复措施作用于不同层级。
临时 vs 持久
临时/持久的区别决定了风险面、修复层级以及事件响应要求。
Credential Denylist at the Serialization Layer
该修复方案:在序列化层设置凭证拒绝列表。在任何标头值写入日志输出之前,先根据拒绝列表检查标头名称。若匹配则将值替换为 [REDACTED]。
CREDENTIAL_HEADERS = {
'authorization',
'cookie',
'x-api-key',
'x-auth-token',
'x-csrf-token',
'proxy-authorization',
}
def sanitize_headers(headers: dict) -> dict:
return {
k: '[REDACTED]' if k.lower() in CREDENTIAL_HEADERS else v
for k, v in headers.items()
}
Denylist 应放置在序列化层,而非日志查询层。日志查询层脱敏:凭证已写入磁盘后才进行处理,原始值依然存在,只是显示时被隐藏。序列化层脱敏:凭证永远不会写入磁盘,原始值不会进入日志文件、日志传输器或日志聚合器。
测试 Denylist
三种测试模式:
- 正向测试:包含 Authorization: Bearer token123 的请求,生成的日志条目中应显示 Authorization: [REDACTED]
- 负面示例:带有 Content-Type: application/json 的请求会生成日志条目,其中值保持不变
- 不区分大小写:AUTHORIZATION: Bearer token123 同样会生成 [REDACTED](HTTP 标头名称不区分大小写)
Denylist 需要维护:新的凭证标头模式(例如自定义 X-Service-Auth 标头)需要显式添加。该修复是结构性的,但并非自我维护。
应用 Denylist
某团队配置 Nginx 访问日志格式以包含所有请求标头,用于调试生产事件。配置如下:
log_format debug_format '$remote_addr - $request - $http_authorization - $http_cookie';
access_log /var/log/nginx/debug.log debug_format;
他们解决了该事件并打算移除调试配置,但更改未在下一次部署周期(7 天后)前到达生产环境。