NGINX速率限制来自JWT令牌的解码值

问题描述

我对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;

JWT Auth for Nginx

,

您可能知道速率限制是通过唯一的IP地址施加的,以获得最佳效果,因此应该使用唯一的jwt值或令牌来限制速率。

您可以按照以下三种方法中的任意一种

  1. 方法

您可以在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;
    }
    ...
}
  1. 方法

您可以从前端在请求的标头(例如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;
    }
    ...
}
  1. 方法

您可以通过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;
    }
    ...
}