Reputation: 2677
I need to apply rate limiting in nginx based on 2 conditions:
1. This is unable to detect the _api key in the Post Request:
limit_req_zone "$arg__api" zone=api_zone:10m rate=30r/m;
limit_req zone=api_zone burst=10 nodelay;
2. This can detect the POST method:
map $request_method $limit {
default "";
POST $binary_remote_addr;
}
limit_req_zone $limit zone=my_zone:10m rate=20r/m;
limit_req zone=my_zone burst=10 nodelay;
So how can I both detect that it is a POST and that the post contains the _api key ?
I just tried detecting the _api key in post with this but it does not work either:
map $request_body $api {
"_api" $binary_remote_addr;
default "";
}
limit_req_zone $api zone=api_api:10m rate=30r/m;
limit_req zone=api_api burst=10 nodelay;
Upvotes: 4
Views: 3577
Reputation: 2677
OK, after many hours of research and a LOT of trial and error I have determined that:
$args only contains GET data
$request_body contains POST data but is only available when using:
proxy_pass
fastcgi_pass
uwsgi_pass
scgi_pass
$request_body is a string and when available is not parsed into JSON so you can't do $request_body_api as you can with $args.
I was NOT able to get this working by directly using $request_body in a map:
map $request_body $body {
default "";
"~*.*(_api)" $binary_remote_addr;
}
limit_req_zone $body zone=body:10m rate=30r/m;
limit_req zone=body burst=5 nodelay;
And the only way I could find of getting this to work was by adding a cookie to the header containing the post, this works but is not very efficient as if the post request is large it is going to consume a lot of unnecessary resources.
add_header Set-Cookie post_data=$request_body;
map $http_cookie $cook_ {
default "";
"~*post_data=.*(\"_api\")" $binary_remote_addr;
}
limit_req_zone $cook zone=cook:10m rate=30r/m;
limit_req zone=cook burst=5 nodelay;
If I have made any incorrect statements/conslusions or if anyone knows of a better method then please let me know, this works but is kind of a hack !
Upvotes: 4