nginx ограничение скорости с заголовком X-Forwarded-For

Вопрос или проблема

Я изучаю лимитирование запросов с использованием модуля nginx HttpLimitReqModule. Однако все запросы приходят с одного и того же IP (балансировщик нагрузки), а реальный IP-адрес находится в заголовках.

Существует ли способ задать лимит запросов в nginx на основе IP из заголовка X-Forwarded-For, а не IP источника?

Да, типичная строка конфигурации для лимитирования запросов выглядит следующим образом:

 limit_req_zone  $binary_remote_addr zone=zone:16m rate=1r/s;

Где $binary_remote_addr является уникальным ключом для ограничителя. Вам следует попробовать изменить его на переменную $http_x_forwarded_for, которая получает значение заголовка X-Forwarded-For. Хотя это увеличит потребление памяти, так как $binary_remote_addr использует сжатый бинарный формат для хранения IP-адресов, а $http_x_forwarded_for — нет.

 limit_req_zone  $http_x_forwarded_for zone=zone:16m rate=1r/s;

Директива limit_req_zone определяет переменную, которая будет использоваться в качестве ключа для группировки запросов.
Обычно используется $binary_remote_addr, а не $remote_addr, потому что это меньше по размеру и экономит место.

Возможно, вы также захотите использовать ngx_http_realip_module.
Это изменит переменные удаленного адреса на адрес, предоставленный в пользовательском заголовке, и также упростит ведение журналов и использование других переменных.

Пример и демонстрация настройки real_ip, используя заголовок.

  • Мы указываем заголовок, из которого брать IP

  • IP клиента будет перезаписан этим значением

  • Тогда мы можем продолжать использовать $binary_remote_addr

    • не всегда используется x-forwarded-for.
  • Этот метод также может помочь с журналами (формат по умолчанию будет работать как $remote_addr, теперь это установлено на перезаписанное значение)

  • Модуль Nginx для использования: ngx_http_realip_module
    Пример настройки с Cloudflare (более одного источника сервера или диапазона IP)

# Ipv4
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;

# Ipv6
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2405:8100::/32;
set_real_ip_from 2a06:98c0::/29;
set_real_ip_from 2c0f:f248::/32;

real_ip_header CF-Connecting-IP;
  • вы можете сохранить это в файл, например: cloudflare_ip.conf и добавить его в conf.d

Вы можете видеть использование

  • set_real_ip_from

    • только запросы, приходящие с этих IP, будут подвержены перезаписи
  • real_ip_header

  • Заголовок, содержащий IP клиента, подключающегося через Cloudflare, это CF-Connecting-IP

  • Руководство Cloudflare руководство

А для лимита запросов

limit_req_zone $binary_remote_addr zone=limit_ip_10rs:10m rate=10r/s;
  • Мы продолжаем использовать $binary_remote_addr

В данном случае лучше использовать модуль realip:

limit_req_zone $binary_remote_addr zone=one:10m rate=12r/m;

server {
    real_ip_header     X-Forwarded-For;
    # docker (за исключением, судя по всему, docker swarm)
    set_real_ip_from   172.16.0.0/12;
    set_real_ip_from   192.168.0.0/16;
    # cloudflare (https://www.cloudflare.com/ips-v4)
    set_real_ip_from   173.245.48.0/20;
    set_real_ip_from   103.21.244.0/22;
    set_real_ip_from   103.22.200.0/22;
    set_real_ip_from   103.31.4.0/22;
    set_real_ip_from   141.101.64.0/18;
    set_real_ip_from   108.162.192.0/18;
    set_real_ip_from   190.93.240.0/20;
    set_real_ip_from   188.114.96.0/20;
    set_real_ip_from   197.234.240.0/22;
    set_real_ip_from   198.41.128.0/17;
    set_real_ip_from   162.158.0.0/15;
    set_real_ip_from   104.16.0.0/13;
    set_real_ip_from   104.24.0.0/14;
    set_real_ip_from   172.64.0.0/13;
    set_real_ip_from   131.0.72.0/22;
    real_ip_recursive  on;

    location / {
        limit_req zone=one burst=5;
        proxy_pass http://backend;
        # proxy_set_header  X-Forwarded-For  $proxy_add_x_forwarded_for;  # nginx < 1.9.7, он добавит переопределенный $remote_addr в X-Forwarded-For
        proxy_set_header  X-Forwarded-For  "$http_x_forwarded_for, $realip_remote_addr";  # nginx >= 1.9.7
    }
}

Вы можете найти подтверждение концепции здесь.

Проблема $proxy_add_x_forwarded_for. Разница между real_ip_recursive = on и real_ip_recursive = off.

Ответ или решение

Для реализации ограничения по количеству запросов в Nginx с использованием заголовка X-Forwarded-For, вы можете воспользоваться модулем ngx_http_realip_module. Это позволит вам переназначить IP-адреса клиентов на основе информации, полученной в заголовках, и использовать оригинальные IP-адреса для настройки ограничения запросов.

Вот пошаговая инструкция, как это сделать:

  1. Включите модуль ngx_http_realip_module. Обычно он включен в стандартных сборках Nginx, но вы можете проверить это с помощью команды nginx -V.

  2. Настройте конфигурацию для использования заголовка X-Forwarded-For. Для этого добавьте соответствующие директивы в ваш конфигурационный файл:

http {
    # Укажите зону для ограничения запросов
    limit_req_zone $binary_remote_addr zone=one:10m rate=12r/m;

    server {
        # Укажите заголовок для получения реального IP
        real_ip_header X-Forwarded-For;

        # Укажите IP-адреса, с которых разрешено доверять заголовку X-Forwarded-For
        set_real_ip_from 172.16.0.0/12;  # Пример: локальная сеть
        set_real_ip_from 192.168.0.0/16;  # Пример: локальная сеть
        set_real_ip_from 173.245.48.0/20;  # Cloudflare IP range
        set_real_ip_from 103.21.244.0/22;  # Cloudflare IP range
        set_real_ip_from 103.22.200.0/22;  # Cloudflare IP range
        # Продолжайте добавлять другие IP-адреса Cloudflare по мере необходимости...

        real_ip_recursive on;  # Включение рекурсивного поиска IP-адреса

        location / {
            limit_req zone=one burst=5;  # Установите лимит запросов
            proxy_pass http://backend;

            # Устанавливаем заголовок X-Forwarded-For
            proxy_set_header X-Forwarded-For "$http_x_forwarded_for, $realip_remote_addr";
        }
    }
}
  1. Проверка настроек. Убедитесь, что настройки правильно применены, перезагрузив Nginx с помощью команды:
sudo nginx -t  # для проверки конфигурации
sudo systemctl reload nginx  # для перезагрузки
  1. Мониторинг логов. Проверьте серверные логи для подтверждения того, что IP-адреса клиентов правильно распознаются и что ограничения на количество запросов работают как ожидается.

Примечания

  • Важно обеспечить, чтобы заголовок X-Forwarded-For действовал только из доверенных источников. Убедитесь, что вы добавили все необходимые диапазоны IP для доверенных прокси-серверов, таких как Cloudflare, или вашей инфраструктуры.

  • Использование переменной $binary_remote_addr в директиве limit_req_zone эффективно с точки зрения использования памяти, так как она хранит IP-адреса в сжатом формате.

Используя данную конфигурацию, вы сможете успешно реализовать ограничение запросов на основе настоящего IP-адреса клиента, полученного через заголовок X-Forwarded-For.

Оцените материал
Добавить комментарий

Капча загружается...