Задача — установить лимит количества запросов с одного IP:
- добавить rate limiter на URI
/user/oauth/refresh_token - число запросов — 5 в минуту с одного IP
- если запросов больше — возвращаем 429 Too Many Requests
Используем NGINX и его модуль ngx_http_limit_req_module.
Содержание
limit_req_zone
Для работы «лимитера» — следует создать зону, в которой будут хранится данные (а именно — кол-во запросов с каждого IP).
Добавляем его в nginx.conf, блок http {}:
... limit_req_zone $binary_remote_addr zone=backend_oauth:10m rate=5r/m; ...
Тут:
$binary_remote_addr— переменная с IP клиентаzone=backend_oauth:10m— создаём зону памяти с именем backend_oauth и размером 10 мегабайт (размер$binary_remote_addrсм. вngx_stream_limit_conn_module)rate=5r/m— максимум 5 запросов в минуту
Also:
-
map $http_branch $app_branch: см. NGINX: мульти-бранч деплой приложения с использованием NGINX map и HTTP Headersmap $status $abnormal: см. NGINX: access лог — логгирование всех запросов, кроме 200set_real_ip_from: см. NGINX: реальный IP в логах при работе за AWS Load Balancer
limit_req
Далее — в конфиге виртуалхоста создаём location, который хотим ограничить, и в него добавляем limit_req:
...
location /v3/user/oauth/refresh_token {
limit_req zone=backend_oauth nodelay;
limit_req_status 429;
try_files $uri $uri/ /index.php?$args;
fastcgi_pass 127.0.0.1:9014;
include fastcgi_params;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
fastcgi_param DOCUMENT_ROOT $root_path;
fastcgi_param SCRIPT_FILENAME $root_path$fastcgi_script_name;
fastcgi_intercept_errors on;
}
...
Проверяем синтаксис, перечитываем конфиги:
[simterm]
root@bttrm-stage-app-2:/home/admin# nginx -t && systemctl reload nginx nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
[/simterm]
Apache benchmark
Проверяем:
[simterm]
$ ab -n 100 -c 10 "https://stage.example.com/v3/user/oauth/refresh_token/"
[/simterm]
И логи:
[simterm]
root@bttrm-stage-app-2:/home/admin# tail -f /var/log/nginx/stage.example.com-access.log | grep 194.***.***.26 194.***.***.26 - - [08/Aug/2019:14:26:29 +0300] "GET /v3/user/oauth/refresh_token/ HTTP/1.1" 404 27 "-" "ApacheBench/2.3" 194.***.***.26 - - [08/Aug/2019:14:26:29 +0300] "GET /v3/user/oauth/refresh_token/ HTTP/1.1" 429 162 "-" "ApacheBench/2.3" 194.***.***.26 - - [08/Aug/2019:14:26:29 +0300] "GET /v3/user/oauth/refresh_token/ HTTP/1.1" 429 162 "-" "ApacheBench/2.3" 194.***.***.26 - - [08/Aug/2019:14:26:29 +0300] "GET /v3/user/oauth/refresh_token/ HTTP/1.1" 429 162 "-" "ApacheBench/2.3" 194.***.***.26 - - [08/Aug/2019:14:26:29 +0300] "GET /v3/user/oauth/refresh_token/ HTTP/1.1" 429 162 "-" "ApacheBench/2.3" ...
[/simterm]
429 отдаётся, всё работает.
NGINX, limit_req и AWS ALB
Упоминают (правда — в 2014 году), что при использовании Load Balancer от AWS — использование $binary_remote_addr может не работать, и вместо него требуется использовать $http_x_forwarded_for, но сейчас работает с $binary_remote_addr. Возможно — благодаря set_real_ip_from (см. NGINX: реальный IP в логах при работе за AWS Load Balancer).

