要在nginx代理层做签名验证并由Node.js 执行 JS 脚本(例如签名校验逻辑),你可以按如下步骤实现:
🌐 一、架构说明
- 客户端请求 → Nginx → Node.js 校验签名脚本 → 放行或拒绝请求
- nginx通过**
auth_request**模块将请求交给Node.js验证签名,结果决定是否转发到后端。
🔐 二、签名验证整体流程
步骤 1:客户端请求带签名参数
GET /api/data?timestamp=1715500000&sign=abc123 HTTP/1.1
Host: yourdomain.com
步骤 2:nginx 配置 auth_request(子请求去验证签名)
server {
listen 80;
server_name yourdomain.com;
location /api/ {
auth_request /auth; # 调用子请求去验证签名
auth_request_set $auth_status $upstream_status;
proxy_pass http://backend_server;
}
location = /auth {
internal;
proxy_pass http://127.0.0.1:3000/verify-signature; # Node.js 校验签名接口
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
}
}
步骤 3:Node.js 实现 /verify-signature 接口
假设你已有 JS 脚本 encrpt.js,可以通过 vm 模块动态执行。
verify-signature.js 示例
const http = require('http');
const url = require('url');
const fs = require('fs');
const vm = require('vm');
// 加载签名脚本
const signScript = fs.readFileSync('./encrpt.js', 'utf8');
const sandbox = {};
vm.createContext(sandbox);
vm.runInContext(signScript, sandbox);
function verifySignature(query) {
const { sign, ...params } = query;
// 假设签名算法为 sandbox.getSign(params)
const expectedSign = sandbox.getSign(params);
return expectedSign === sign;
}
const server = http.createServer((req, res) => {
if (req.url.startsWith('/verify-signature')) {
const parsedUrl = url.parse(req.url, true);
const isValid = verifySignature(parsedUrl.query);
if (isValid) {
res.writeHead(200);
res.end('OK');
} else {
res.writeHead(401);
res.end('Unauthorized');
}
} else {
res.writeHead(404);
res.end('Not Found');
}
});
server.listen(3000, () => {
console.log('Signature verifier running on http://localhost:3000');
});
步骤 4:测试
- 正确签名时,nginx 子请求返回 200,主请求放行;
- 错误签名时,nginx 子请求返回 401,主请求被拒绝。
✅ 补充建议
- 使用
crypto代替纯 JS 算法更安全(如 HMAC SHA256) - 签名参数中加入
timestamp和nonce防重放攻击 auth_request子请求应避免携带过多 headers
🔐 三、Nginx + Node.js 签名验证项目结构示例
以下是一个完整的 Nginx + Node.js 签名验证项目结构示例,适用于在 Nginx 层对 API 请求进行签名校验,Node.js 提供校验逻辑的方案。
📁 项目结构
sign-proxy-project/
├── nginx/
│ └── nginx.conf # Nginx 配置文件
├── node-sign-server/
│ ├── encrpt.js # JS 签名算法逻辑
│ ├── verify-signature.js # Node.js HTTP 校验服务
│ └── package.json # Node.js 依赖配置
└── README.md
📘 说明
✅ encrpt.js — 签名逻辑(例:HMAC)
const crypto = require('crypto');
function getSign(params, secret = 'your-secret-key') {
const sortedKeys = Object.keys(params).sort();
const str = sortedKeys.map(k => `${k}=${params[k]}`).join('&');
return crypto.createHmac('sha256', secret).update(str).digest('hex');
}
// 暴露函数给 vm 使用
this.getSign = getSign;
✅ verify-signature.js — Node.js 签名校验服务
const http = require('http');
const url = require('url');
const fs = require('fs');
const vm = require('vm');
// 加载加密脚本
const code = fs.readFileSync(__dirname + '/encrpt.js', 'utf8');
const sandbox = {};
vm.createContext(sandbox);
vm.runInContext(code, sandbox);
// 签名校验函数
function verify(query) {
const { sign, ...params } = query;
const expected = sandbox.getSign(params);
return expected === sign;
}
// 启动服务
http.createServer((req, res) => {
if (req.url.startsWith('/verify-signature')) {
const parsed = url.parse(req.url, true);
if (verify(parsed.query)) {
res.writeHead(200);
res.end('OK');
} else {
res.writeHead(401);
res.end('Invalid Signature');
}
} else {
res.writeHead(404);
res.end('Not Found');
}
}).listen(3000, () => {
console.log('Signature server running at http://localhost:3000');
});
✅ nginx.conf — Nginx 配置示例
events {}
http {
upstream backend_server {
server 127.0.0.1:8000;
}
server {
listen 8080;
location /api/ {
auth_request /auth;
proxy_pass http://backend_server;
}
location = /auth {
internal;
proxy_pass http://127.0.0.1:3000/verify-signature;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
}
}
}
✅ package.json(Node.js 项目)
{
"name": "node-sign-server",
"version": "1.0.0",
"main": "verify-signature.js",
"dependencies": {}
}
用
npm init -y初始化即可。
▶️ 启动方式
-
启动 Node 服务:
cd node-sign-server node verify-signature.js -
启动 Nginx(使用本地 nginx 并加载配置):
nginx -c /full/path/to/nginx.conf -
发请求测试:
curl "http://localhost:8080/api/data?timestamp=1715500000&foo=bar&sign=xxx"

817

被折叠的 条评论
为什么被折叠?



