Token-based лімітування кількості з'єднань
Усі знають про ліміти кількості підключень з одного IP (IP-based), але що робити, якщо ми хочемо обмежити кількість підключень до деякого API на один токен авторизації?
І не важливо, скільки різних IP буде використано.
Частина конфігу nginx:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | map $request_uri $client_token {
"~*(?i)(token=)([a-f0-9]{32})" $2; # regex return <32str>
default ""; # Fallback to limit_req_zone:global
}
limit_req_zone $binary_remote_addr zone=global:32m rate=100r/s; # Rule_1
limit_req_zone $client_token zone=tokenlimit:32m rate=5r/s; # Rule_2
limit_req zone=global burst=25;
server {
location / {
index index.html;
root /var/www/html;
}
location = /api {
index index.html;
root /var/www/api/html;
limit_req zone=tokenlimit burst=5 nodelay; # api location
limit_req zone=global; # Fallback
limit_req_status 429; # 503
|
Приклад змішаного блокування
Імітуємо безліч підключень з хоста A без токена.
ab -n 999 -c 5 "http://api.tld/api?id=letmein"
Перевіряємо та отримуємо блокування IP A
Незалежно від наявності токена, він перевищив правило Rule_1.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | curl -v "http://api.tld/api?token=00000000000000000000000000000000" < HTTP/1.1 429 Too Many Requests < Server: nginx < Date: Sun, 22 Jun 2024 20:03:37 GMT < Content-Type: text/html < Content-Length: 162 < Connection: keep-alive < <html> <head><title>429 Too Many Requests</title></head> <body> <center><h1>429 Too Many Requests</h1></center> <hr><center>nginx</center> </body> </html> |
IP B при цьому підключається без проблем
Він не перевищив ні кількість підключень з одного IP Rule_1, ні кількість підключень на один токен Rule_2.
1 2 3 4 5 6 7 8 9 10 | curl -v "http://api.tld/api?token=00000000000000000000000000000000" < HTTP/1.1 200 OK < Server: nginx < Date: Sun, 22 Jun 2024 20:04:18 GMT < Content-Type: text/plain; charset=utf-8 < Content-Length: 801 < Connection: keep-alive < X-App-TOKEN: 00000000000000000000000000000000 |
Приклад перевищення ліміту на один токен
Хост A
Імітуємо безліч підключень з хоста A використовуючи токен (111).
1 | ab -n 999 -c 5 "http://api.tld/api?token=11111111111111111111111111111111" |
Отримуємо блокування токена
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | curl -v "http://api.tld/api?token=11111111111111111111111111111111" < HTTP/1.1 429 Too Many Requests < Server: nginx < Date: Sun, 22 Jun 2024 20:10:48 GMT < Content-Type: text/html < Content-Length: 162 < Connection: keep-alive < <html> <head><title>429 Too Many Requests</title></head> <body> <center><h1>429 Too Many Requests</h1></center> <hr><center>nginx</center> </body> </html> |
Хост B
Пробуємо використовувати цей же токен (111) з хоста B.
Отримуємо таке ж блокування токена
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | curl -v "http://api.tld/api?token=11111111111111111111111111111111" < HTTP/1.1 429 Too Many Requests < Server: nginx < Date: Sun, 22 Jun 2024 20:12:42 GMT < Content-Type: text/html < Content-Length: 162 < Connection: keep-alive < <html> <head><title>429 Too Many Requests</title></head> <body> <center><h1>429 Too Many Requests</h1></center> <hr><center>nginx</center> </body> </html> |
Пробуємо використати інший токен (000) з хоста B.
Успішне підключення
1 2 3 4 5 6 7 8 9 10 | curl -v "http://api.tld/api?token=00000000000000000000000000000000" < HTTP/1.1 200 OK < Server: nginx < Date: Sun, 22 Jun 2024 20:09:07 GMT < Content-Type: text/plain; charset=utf-8 < Content-Length: 805 < Connection: keep-alive < X-App-TOKEN: 00000000000000000000000000000000 |
Таким чином, можна комбінувати різні ліміти, ґрунтуючись не тільки на IP, але й на параметрах запиту або location.
Оригінальний пост на SecOps.it Blog • Token-based лімітування кількості з'єднань