问题描述
我对Nginx速率限制有疑问。
是否可以基于JWT令牌的解码值进行速率限制?我在文档中找不到任何类似的信息。
或者即使有一种通过创建纯自定义变量(使用LuaJIT)来进行速率限制的方法,该变量也会从我解码的JWT中分配一个值-也会起作用。
事实是,limit_req
模块似乎在请求到达luaJIT阶段之前就已执行完毕,因此为时已晚!
解决方法
Nginx的JWT身份验证
nginx-jwt
是Nginx服务器的Lua脚本(运行HttpLuaModule
),它允许您将Nginx用作现有HTTP服务集之前的反向代理并保护它们的安全(身份验证) / authorization),在Authorization请求标头中使用受信任的JSON Web令牌(JWT),而无需对支持服务本身进行任何更改。
重要提示:nginx-jwt
是一个Lua脚本,旨在在安装了HttpLuaModule
的Nginx服务器上运行。但是最终,它的依赖关系需要Nginx的OpenResty
发行版中可用的组件。因此,建议您将OpenResty
用作Nginx服务器,并且这些说明进行了假设。
配置
目前,nginx-jwt仅支持对称密钥(alg = hs256),这就是为什么需要使用下面的共享JWT机密配置服务器的原因。
1。在Nginx主机上导出JWT_SECRET环境变量,将其设置为等于您的JWT机密。然后将其公开给Nginx服务器:
# nginx.conf:
env JWT_SECRET;
2。如果您的JWT机密是Base64(URL安全)编码的,请在Nginx主机上导出JWT_SECRET_IS_BASE64_ENCODED环境变量,并将其设置为true。然后将其公开给Nginx服务器:
# nginx.conf:
env JWT_SECRET_IS_BASE64_ENCODED;
,
您可能知道速率限制是通过唯一的IP地址施加的,以获得最佳效果,因此应该使用唯一的jwt值或令牌来限制速率。
您可以按照以下三种方法中的任意一种
- 方法
您可以在limit_req_zone中直接使用jwt令牌。
http {
...
limit_req_zone $http_authorization zone=req_zone:10m rate=5r/s;
}
conf.d / default.conf
server {
listen 80;
listen [::]:80;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
if ($http_authorization = "") {
return 403;
}
location /jwt {
limit_req zone=req_zone burst=10 nodelay;
return 200 $http_authorization;
}
...
}
- 方法
您可以从前端在请求的标头(例如http_x_jwt_decode_value)中发送已解码的jwt值,然后可以在limit_req_zone中使用它。
http {
...
limit_req_zone $http_x_jwt_decode_value zone=req_zone:10m rate=5r/s;
}
conf.d / default.conf
server {
listen 80;
listen [::]:80;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
if ($http_x_jwt_decode_value = "") {
return 403;
}
location /jwt {
limit_req zone=req_zone burst=10 nodelay;
return 200 $http_x_jwt_decode_value;
}
...
}
- 方法
您可以通过njs javascript模块,perl模块或lua模块在nginx中解码jwt令牌,并将其分配给变量,然后将其用于速率限制。
说明:这里我只是解码了jwt值,并检查了它是否不为空,您可以使用它来与jwt解码值一起使用。
jwt_example.js
function jwt(data) {
var parts = data.split('.').slice(0,2)
.map(v=>String.bytesFrom(v,'base64url'))
.map(JSON.parse);
return { headers:parts[0],payload: parts[1] };
}
function jwt_payload_sub(r) {
return jwt(r.headersIn.Authorization.slice(7)).payload.sub;
}
export default {jwt_payload_sub}
nginx.conf
# njs module
load_module modules/ngx_http_js_module.so;
http {
...
include /etc/nginx/conf.d/*.conf;
js_import main from jwt_example.js;
js_set $jwt_payload_sub main.jwt_payload_sub;
limit_req_zone $jwt_payload_sub zone=req_zone:10m rate=5r/s;
}
conf.d / default.conf
server {
listen 80;
listen [::]:80;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
if ($jwt_payload_sub = "") {
return 403;
}
location /jwt {
limit_req zone=req_zone burst=10 nodelay;
return 200 $jwt_payload_sub;
}
...
}