Назад | Перейти на главную страницу

Nginx: ограничение скорости обхода с заголовком

Этот ответ идеально подходит для обхода ограничения скорости с помощью IP-адресов.

Если мне нужно обойти ограничение скорости с помощью секретного заголовка, как мне этого добиться?

Ссылка:

http {
    geo $whitelist {
       default 0;
       # CIDR in the list below are not limited
       1.2.3.0/24 1;
       9.10.11.12/32 1;
       127.0.0.1/32 1;
    }
    map $whitelist $limit {
        0     $binary_remote_addr;
        1     "";
    }
    limit_conn_zone      $limit    zone=connlimit:10m;

    limit_conn           connlimit 5;
    limit_conn_log_level warn;   # logging level when threshold exceeded
    limit_conn_status    503;    # the error code to return

FWIIW, я тоже смотрел на другой "странный" ответ на вопрос, на который вы ссылаетесь - он был написан в 2011 году, сегодня в 2017 году он получил только 3 положительных голоса по сравнению с 23 положительными голосами за более поздний ответ примерно в 2014 году, который вы цитируете. Возможно, несколько удивительно, но более старый игнорируемый ответ на самом деле работает без каких-либо проблем!

Вот мой взгляд на полную конфигурацию MVP, полностью протестированную:

server {
    listen 7461;
    error_page 429 = @slowdown;
    if ($http_x_secret_header != secret_value) {
        return 429;
    }
    location @slowdown {
        #limit_...
        return 200 "$uri: slowed down\n";
    }
    location / {
        return 200 "$uri: very fast\n";
    }
}

Вот тестирование, которое покажет вам, что все это работает, включая тот факт, что правильный 200 OK код возвращается:

%curl -H "X-Secret-Header: secret_value" localhost:7461/important/path/
/important/path/: very fast

%curl -H "X-Secret-Header: wrong_value" localhost:7461/important/path/
/important/path/: slowed down

%curl -v localhost:7461/important/path/ | & fgrep -e HTTP/ -e /important
> GET /important/path/ HTTP/1.1
< HTTP/1.1 200 OK
/important/path/: slowed down
%

Так что да, error_page перенаправление тоже действительно работает!


Позвольте мне объяснить причину странного error_page ответ - в nginx можно делать и то, и другое внешний перенаправляет (видны клиенту), а также внутренний перенаправляет (выполняется внутри компании, без промежуточных ответов клиенту).

Это внутреннее и внешнее различие - очень могущественный концепция, без которой много прохладный ухищрения было бы невозможно, поскольку язык конфигурации достаточно прост, чтобы ограничить количество директив, доступных изнутри if оператор, а также не разрешать вложенные if заявления.

Итак, вместо этого с внутренним перенаправлением $uri могут быть изменены внутри, в результате чего ваш запрос будет перемещаться между несколькими независимыми местоположениями (подумайте о каждом location как состояние в DFA (детерминированный конечный автомат)), пока не будет достигнут желаемый результат (в качестве крайнего примера, взгляните на http://mdoc.su/, как видно на nginx.conf 2016).


Чтобы обобщить, в приведенном выше примере:

  • мы перепрофилируем 429 error_page действовать как internal перенаправить на internal location, а затем обработать такие internal location точно так же, как и не внутреннее расположение, за исключением добавления некоторых дополнительных переменных или директив;

  • мы также используем = параметр для error_page директива, указывающая nginx не отправлять 429 код обратно клиенту, но вместо этого пусть дальнейшая обработка диктует, каким должен быть окончательный код состояния.

Обычная причина этих вопросов заключается в том, что большинство этих директив нельзя использовать в контексте if заявление, следовательно, как можно было бы условно указать разные пределы?

Ответ заключается в использовании промежуточных переменных - так же, как в связанном ответе, используйте установку пределов с помощью переменных, где впоследствии значения этих переменных будут различаться в зависимости от map или if заявление.

http {
    map $http_x_secret_header $limit {
        default      $binary_remote_addr;
        secretvalue  "";
    }
    limit_conn_zone      $limit    zone=connlimit:10m;
    …

Ссылка: