nginx 不直接加密敏感数据,应由后端服务完成sm4/aes加密,或通过openresty+lua在边缘层轻量处理;密钥须从vault/kms动态获取,全链路强制https,日志禁止明文记录。

实现 Nginx 代理后端集群对敏感数据的二次加密,核心在于:Nginx 本身不直接参与业务层加解密,需通过上游服务协同完成;真正可行的方案是让后端服务在收到 Nginx 转发的请求后,对特定字段(如身份证号、手机号、token)做二次加密,或由 Nginx 利用 ngx_http_js_module(配合 JavaScript)或 OpenResty + Lua 在边缘层做轻量级加解密。纯官方 Nginx 不支持 AES/SM4 等业务级加密,必须扩展。
明确加密位置与责任边界
敏感数据加密应在应用层(后端服务)完成,Nginx 定位为“安全网关”而非“加密引擎”。常见误操作是试图在 Nginx 配置里写加密逻辑——官方模块无此能力。正确分工:
- Nginx 负责识别敏感字段(如请求体中的 idCard、phone),提取并透传给后端
- 后端服务接收后,对这些字段执行国密 SM4 或 AES-256 加密,并存入数据库或返回
- 若需 Nginx 层预处理(如脱敏展示、签名验签),必须引入 OpenResty 或 NJS
使用 OpenResty + Lua 实现请求体字段加密
OpenResty 内置 LuaCrypto 或 lua-resty-nettle 库,支持 SM4/AES。适用于需在入口统一加密字段再转发的场景(例如所有 /api/user 接口的 phone 字段强制加密):
- 安装 OpenResty,启用 lua_shared_dict 缓存密钥(避免每次读文件)
- 在 access_by_lua_block 中解析 JSON 请求体,定位敏感 key
- 调用 resty.nettle.sym.encrypt 对值加密(注意 Base64 编码、IV 随机生成并附带)
- 重写请求体后调用 ngx.req.set_body_data(),再 proxy_pass
示例片段(SM4-ECB,仅示意):
local cipher = require "resty.nettle.sym"local enc = cipher:new("sm4", "your-32-byte-key")
local encrypted = enc:encrypt(ngx.var.phone_raw)
后端服务承担主要加密职责(推荐)
更合理、可维护性更高的方式:Nginx 仅做路由、限流、鉴权;后端框架(Spring Boot / Gin / Flask)统一拦截器中处理加解密:
- 定义注解(如 @EncryptField("idCard,phone"))标记 DTO 字段
- 全局 Filter/Interceptor 解析请求体,对标注字段执行 SM4 加密(密钥从 Vault 或 KMS 获取)
- 响应时对 @DecryptField 字段自动解密,保证前后端协议透明
- Nginx 可配合添加请求头 X-Encrypt-Mode: sm4,供后端判断是否启用加密
传输与密钥安全必须同步落地
加密无效若密钥泄露或传输未保护:
- 所有代理链路强制 HTTPS(Nginx 开启 TLS 1.2+,禁用弱密码套件)
- 加密密钥严禁硬编码,使用 HashiCorp Vault 或阿里云 KMS 动态拉取
- 避免在日志中打印原始敏感字段(Nginx access_log 中用 $http_x_masked_phone 替代明文)
- 后端加解密操作需记录审计日志(谁、何时、对哪条数据做了加密),但日志中不得含原文











