Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NGINX rate limitting by decoded values from JWT token

I have a question regarding NGINX rate limiting.

Is it possible to do rate limiting based on the decoded value of JWT token? I cannot find any information like this in the docs.

Or even if there is a way of doing rate limiting by creating pure custom variable (using LuaJIT) which will be assigned with a value from my decoded JWT - will also do the job. The thing is that the limit_req module seems to execute way before the request reaches the luaJIT stage so its already too late!

A solution will be appreciated.

like image 915
Marcin Majewski Avatar asked Oct 08 '20 13:10

Marcin Majewski


1 Answers

As you may know that rate limit is applied through unique ip address for best result you should use unique jwt value or token to rate limit.

You can follow any of these 3 methods

  1. Method

You can directly use jwt token in limit_req_zone.

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. Method

You can send decoded jwt value from frontend in reqest header like http_x_jwt_decode_value and then you can use that in 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. Method

You can decode jwt token in nginx though njs javascript module or perl module or lua module and assign it to variable then use that to rate limit.

Description: here i just decoded jwt value and checked if its not empty you can use it to work with and jwt decoded value.

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;
    }
    ...
}
like image 97
Chandan Avatar answered Nov 16 '22 01:11

Chandan