Задача – установить лимит количества запросов с одного 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).