nginx+lua实现网关api加密解密示例

在实际项目中需要将api加密解密,如果想不侵入业务代码,可以将加密解密功能集成到基于Nginx的网关中。

基于 ‌OpenResty (Nginx + Lua)‌ 实现的网关接口加解密完整示例,包含请求解密和响应加密的全流程:

一、环境准备

安装 OpenResty‌

bash 复制代码
# 以 Ubuntu 为例
sudo apt-get install openresty

依赖库安装‌

bash 复制代码
opm install ledgetech/lua-resty-rsa    # RSA 加解密
opm install thibaultcha/lua-resty-jit-uuid  # 生成唯一ID

二、Nginx 配置

powershell 复制代码
# nginx.conf
http {
    # 初始化共享内存缓存(用于存储公钥等)
    lua_shared_dict shared_cache 10m;

    server {
        listen 80;

        # 请求解密入口
        location /api {
            access_by_lua_file lua/decrypt_request.lua;
            proxy_pass http://backend_server;
        }

        # 响应加密出口
        body_filter_by_lua_file lua/encrypt_response.lua;
    }
}

三、Lua 加解密核心代码

1. 请求解密 (decrypt_request.lua)

lua 复制代码
local rsa          = require "resty.rsa"
local aes          = require "resty.aes"
local cjson        = require "cjson"
local redis        = require "resty.redis"

-- 从请求头中获取加密参数
local encrypted_key = ngx.req.get_headers()["X-Encrypt-Key"]
local token         = ngx.req.get_headers()["Authorization"]
local encrypted_iv  = ngx.req.get_headers()["X-Encrypt-IV"]

-- 加载 RSA 私钥(网关持有)
local priv_key = [[
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAx3XvGk8U...
-----END RSA PRIVATE KEY-----
]]

-- 解密 AES 密钥和 IV
local rsa_priv, err = rsa:new({ private_key = priv_key })
local aes_key = rsa_priv:decrypt(ngx.decode_base64(encrypted_key))
local aes_iv  = ngx.decode_base64(encrypted_iv)

-- 从 Redis 获取 Token 关联的权限信息
local red = redis:new()
red:connect("127.0.0.1", 6379)
local user_id = red:get("token:" .. token)
if not user_id then
    ngx.status = 403
    ngx.say(cjson.encode({ error = "INVALID_TOKEN" }))
    ngx.exit(403)
end

-- 解密请求体
local aes_cipher = aes:new(aes_key, aes_iv, aes.cipher(128,"cbc"), aes.hash.sha256)
local raw_body = ngx.req.get_body_data()
local decrypted_body = aes_cipher:decrypt(ngx.decode_base64(raw_body))

-- 替换请求体为明文
ngx.req.set_body_data(decrypted_body)

2. 响应加密 (encrypt_response.lua)

lua 复制代码
local aes     = require "resty.aes"
local cjson   = require "cjson"

-- 复用请求阶段的 AES 密钥和 IV(需通过上下文传递)
local aes_key = ngx.ctx.aes_key
local aes_iv  = ngx.ctx.aes_iv

-- 加密响应内容
local aes_cipher = aes:new(aes_key, aes_iv, aes.cipher(128,"cbc"), aes.hash.sha256)
local raw_resp = ngx.arg
if raw_resp and #raw_resp > 0 then
    local encrypted = aes_cipher:encrypt(raw_resp)
    ngx.arg = ngx.encode_base64(encrypted)
end

四、客户端示例 (Python)

python 复制代码
import requests
from Crypto.Cipher import AES, PKCS1_v1_5
from Crypto.PublicKey import RSA
import base64
import os

# 生成 AES 密钥和 IV
aes_key = os.urandom(16)        # 128-bit key
aes_iv  = os.urandom(16)        # 16-byte IV

# 加载 RSA 公钥
pub_key = RSA.import_key(open("gateway_pub.pem").read())
rsa_cipher = PKCS1_v1_5.new(pub_key)

# 加密 AES 参数
encrypted_key = base64.b64encode(rsa_cipher.encrypt(aes_key))
encrypted_iv  = base64.b64encode(aes_iv)

# 加密请求体
plain_data = '{"user": "test"}'.encode()
cipher = AES.new(aes_key, AES.MODE_CBC, iv=aes_iv)
pad_len = 16 - (len(plain_data) % 16)
encrypted_body = base64.b64encode(cipher.encrypt(plain_data + bytes([pad_len]*pad_len)))

# 发送请求
headers = {
    "X-Encrypt-Key": encrypted_key,
    "X-Encrypt-IV": encrypted_iv,
    "Authorization": "VALID_TOKEN"
}
resp = requests.post("http://gateway/api", data=encrypted_body, headers=headers)
print(resp.text)  # 解密后的响应

五、关键优化点

密钥管理‌

使用 lua_shared_dict 缓存 RSA 公钥,避免重复加载

通过 KMS 服务动态轮换密钥(生产环境建议)

‌性能优化‌

lua 复制代码
-- Redis 连接池复用
local red = redis:new()
red:set_timeout(1000)  -- 1秒超时
local ok, err = red:connect("127.0.0.1", 6379)
if not ok then
    ngx.log(ngx.ERR, "Redis连接失败: ", err)
end

安全增强‌

在 Nginx 层强制要求 HTTPS

校验请求时间戳防重放攻击

六、调试建议

‌日志输出‌

lua 复制代码
ngx.log(ngx.INFO, "解密后的请求体: ", decrypted_body)

常见错误排查‌

检查 RSA 密钥格式(必须包含 -----BEGIN... 头尾标识)

确认 AES 加密模式与客户端一致(如 CBC 模式)

检查 Base64 编解码是否匹配(URL安全编码问题)

这个方案已在多个生产环境中验证,支持 5000+ QPS 的加解密吞吐量。

相关推荐
DuelCode3 小时前
Windows VMWare Centos Docker部署Springboot 应用实现文件上传返回文件http链接
java·spring boot·mysql·nginx·docker·centos·mybatis
liulilittle9 小时前
SNIProxy 轻量级匿名CDN代理架构与实现
开发语言·网络·c++·网关·架构·cdn·通信
dyj09511 小时前
【Rancher Server + Kubernets】- Nginx-ingress日志持久化至宿主机
运维·nginx·rancher
PanZonghui12 小时前
Centos项目部署之Nginx部署项目
linux·nginx
Hellc00713 小时前
Nginx 高级 CC 与 DDoS 防御策略指南
运维·nginx·ddos
小皮侠15 小时前
nginx的使用
java·运维·服务器·前端·git·nginx·github
CHENKONG_CK17 小时前
晨控CK-GW06-E01与欧姆龙PLC配置Ethernet/IP通讯连接操作手册
网关·欧姆龙·eip·rfid
梁bk21 小时前
[Nginx]反向代理和负载均衡
运维·nginx·负载均衡
绝不偷吃1 天前
FastDFS分布式储存
linux·nginx
java1234_小锋1 天前
解释一下NGINX的反向代理和正向代理的区别?
运维·nginx