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 的加解密吞吐量。

相关推荐
weixin_408099671 小时前
Lua请求文字识别ocr api
图像处理·人工智能·后端·ocr·lua·api·文字识别
IntMainJhy1 小时前
Flutter flutter_animate 第三方库 动画的鸿蒙化适配与实战指南
nginx·flutter·harmonyos
上海合宙LuatOS9 小时前
LuatOS扩展库API——【libfota】远程升级
物联网·junit·lua·luatos
mfxcyh13 小时前
使用MobaXterm配置nginx
java·服务器·nginx
阿里巴巴首席技术官13 小时前
通过纯Nginx实现一个简单的文件上传功能
运维·nginx
就叫飞六吧14 小时前
Docker Hub 上主流的nginx发行
java·nginx·docker
RePeaT18 小时前
【Nginx】前端项目部署与反向代理实战指南
前端·nginx
wicb91wJ618 小时前
Nginx反向代理与负载均衡配置详解
运维·nginx·负载均衡
蜡台19 小时前
centos 8 安装 nginx-1.29.8 及相关配置教程
linux·nginx·centos
困惑阿三19 小时前
Nginx 域名绑定与 HTTPS 配置指南
运维·nginx·https·ssl