Nginx作为反向代理时,回源请求头中经常需要携带Authorization、Cookie等敏感凭据,以便上游服务完成身份校验。但默认的访问日志记录策略可能把这些字段原样写入access.log,一旦日志被集中采集或误发到第三方平台,就会造成令牌泄露。要解决这个问题,不能只依赖关闭日志,而是需要理解Nginx回源请求头的生成顺序、日志格式变量的取值来源,以及如何在不影响上游认证的前提下对敏感字段进行脱敏。

一、Nginx回源携带Credentials的典型配置
在Nginx反向代理场景中,客户端请求到达Nginx后,Nginx会重新构造一个发往上游服务的请求。默认情况下,Nginx并不会自动转发所有客户端请求头,尤其是Authorization、Cookie这类带有身份信息的字段。为了让上游服务能够识别用户身份,通常需要显式使用proxy_set_header指令把它们塞进回源请求。
下面是一个常见的配置片段:
location /api/ {
proxy_pass http://upstream_server;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Authorization $http_authorization;
proxy_set_header Cookie $http_cookie;
}
这里的$http_authorization对应客户端请求中的Authorization头,$http_cookie对应Cookie头。如果客户端没有携带这些头,变量为空,回源请求中就不会包含对应字段。需要特别注意的是,如果客户端请求头名称包含下划线,Nginx默认会忽略它,但Authorization和Cookie不在此列,因此直接读取变量是可靠的。显式传递凭据的好处是控制精确,但同时也埋下了日志泄露的隐患,因为同一个变量可以被日志格式直接引用。
有些开发者会误以为只要不配置access_log就不会有记录,但实际上Nginx的默认日志格式可能已经包含了$request,当用户把身份令牌放在URL查询参数中时,例如/api/user?token=abcd1234,这个令牌就会原封不动地进入日志文件。因此,即使不记录请求头,凭据依然可能通过请求行泄露。
二、日志记录凭据的常见成因与风险
Nginx默认的combined日志格式为:$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"。它不会直接记录Authorization或Cookie,但如果管理员自行扩展了日志格式,情况就完全不同了。很多团队为了排查问题,会把大量请求头变量写入log_format,其中就可能包含敏感凭据。
例如以下配置就会把Authorization和Cookie值完整输出到debug.log:
log_format debug '$remote_addr "$http_authorization" "$http_cookie" "$request"'; access_log /var/log/nginx/debug.log debug;
一旦日志文件被攻击者读取,或者被日志采集系统上传到Elasticsearch等平台,有效的Bearer Token或会话Cookie就会直接暴露。即使日志只对内部开放,也可能因为权限配置不当而被越权访问。另外,Nginx的错误日志在特定情况下也会记录请求头,例如上游返回非正常状态码时触发的debug日志。凭据泄露不止发生在访问日志,错误日志、代理缓存键、甚至第三方模块的调试输出都可能包含敏感信息。
另一个常见的风险来源是URL查询参数。很多旧系统会把Access Token放在query string中,而Nginx的$request变量会完整记录请求行,包括问号后面的部分。即使格式中没有显式添加$arg_token,只要记录了$request,查询参数就被包含在内。因此,除了调整日志格式,还需要引导客户端改为通过Authorization头传递凭据,从源头避免敏感数据进入URL。
三、安全实践:日志脱敏与条件传递凭据
要彻底阻断凭据写入日志,最直接的做法是不在log_format中引用任何敏感头变量。如果业务确实需要记录Authorization信息用于审计,应该进行脱敏处理,只保留类型或哈希后的片段,而不是完整令牌。Nginx的map指令可以非常方便地在日志层面对变量做转换。
map $http_authorization $log_auth_safe {
default "REDACTED";
~^Bearer\s+(.+)$ "Bearer ***";
}
log_format secure '$remote_addr $log_auth_safe "$request"';
access_log /var/log/nginx/access.log secure;
上面的配置会检查Authorization头,如果它以Bearer开头,日志中只显示Bearer ***,任何其他值则显示REDACTED。这样既保留了请求是否携带凭据的信息,又不会泄露真实令牌。需要注意的是,map块中的正则表达式必须在http上下文定义,而日志格式在使用时才会对变量求值,因此不会影响回源请求本身的Authorization头。
除了日志脱敏,还可以在回源时使用条件传递来减少敏感头暴露面。例如,只有访问特定路径或来自可信网段的请求才转发Authorization,否则回源请求不携带该头。Nginx的if指令虽然不推荐在location中滥用,但配合set和proxy_set_header可以实现简单的条件逻辑。更好的做法是使用map根据请求属性动态生成待传递的凭据变量。
四、进阶方案:使用map与变量隔离敏感头
当系统同时需要完整凭据用于回源认证,又要保证日志中看不到明文令牌时,可以采用变量隔离的策略。核心思想是:在Nginx内部维护一个原始凭据变量,只在proxy_set_header中使用它;日志格式则引用另一个经过脱敏处理的变量。两者互不干扰,从架构上杜绝了不小心把原始变量写进日志的可能。
map $http_authorization $upstream_authorization {
default $http_authorization;
}
map $http_authorization $log_authorization {
default "REDACTED";
~^Bearer\s+(.+)$ "Bearer $1";
}
server {
location /api/ {
proxy_pass http://upstream_server;
proxy_set_header Authorization $upstream_authorization;
access_log /var/log/nginx/api_access.log secure;
}
}
在这个例子中,$upstream_authorization保存原始Authorization头,专门用于回源请求;$log_authorization则输出脱敏后的值。日志格式secure里只引用$log_authorization,即使以后有人修改日志格式,只要不主动把$upstream_authorization加进去,原始凭据就不会出现在日志中。这种隔离方式比单纯修改日志格式更稳健,因为它把敏感变量的使用边界划分得很清楚。
如果上游服务需要同时接收Cookie,处理方式类似。可以单独创建一个$log_cookie_safe变量,用正则把Cookie值中的关键部分替换为星号。但Cookie结构复杂,通常建议完全不记录Cookie字段,除非有明确的合规审计需求。对于确实需要记录的场景,尽量只记录Cookie名称和过期时间,不要记录value本身。
另外,生产环境还应配合日志轮转和权限控制。将access.log的文件权限设置为仅root或日志采集用户可读,避免其他系统账户查看。同时定期清理旧日志,防止历史凭据遗留。如果使用的是集中式日志平台,应在采集端增加过滤规则,对authorization、cookie等字段进行掩码,形成纵深防御。
Nginx回源Credentials日志脱敏修改时间:2026-08-23 14:55:19