Использование limit_except для запрета всего, кроме GET, HEAD и POST

Как использовать nginx limit_except отрицать все, кроме типичных методов http (т.е. GET а также POST) в типичной конфигурации сайта nginx (например, в блоге)? Вообразите, что это должно было быть в server блок и блоки были настроены на перенаправление всего трафика в https а также www,

Наглядный пример того, как этого добиться, было бы здорово.

Я понимаю, что несколько противоречивый способ сделать это был:

add_header Allow "GET, POST, HEAD" always;
if ( $request_method !~ ^(GET|POST|HEAD)$ ) {
return 405;
}

Однако, если это зло, имеет смысл изучить альтернативный метод.

2 ответа

В действительности нет ничего другого, кроме добавления того, что уже упоминалось в документации, к вашему блоку сервера:

server {
  server_name www.example.org;
  root /var/www/blog;

  ...
  # add this line (HEAD is implcicit - its a just special case of GET)
  limit_except GET POST { deny  all; }
  ...

}

Это не обязательно лучшая идея, чтобы просто сделать это, хотя:

Прежде чем выбрать настройку любого метода, обратите внимание на разницу между 405 и 403.

  • 403 относится к клиенту, осуществляющему доступ, который не авторизован для выполнения этого запроса.
  • 405 относится к серверу, не разрешающему этот метод для этого URI.

Использование комбинации обоих допустимо: вы можете сказать пользователям, что PROPFIND здесь не разрешен, но затем, когда клиент пытается PUT, все же скажите ему, что, хотя это может быть понятным методом, конкретное требование по-прежнему запрещено.

Что вы можете настроить limit_except является лишь подмножеством ограничений, которые могут привести к 403 - я не вижу способ вызвать 405 с помощью limit_except это было бы более понятно, чем просто if сразу.

Вот (непроверенный) пример, который объединяет ответы 401, 403 и 405 и должен уточнить их приоритетность в типичной конфигурации:

server {
    listen 192.0.2.1 ssl http2;
    server_name example.org;
    ssl_certificate_key /etc/ssl/private/example.org.key;

    # nobody shall be able to delete anything on this server
    if ($request_method = DELETE)
    {
        # the concerns about using if are not applicable
        # if the block only contains "return" or "rewrite .. last"
        return 405;
    }

    root /var/www/html;

    location /.well-known {
        alias /var/www/well-known;
    }
    location / {
        # logging in from specific IPs grants acces without HBA login
        satisfy any;
        allow 203.0.113.0/24;
        deny all;
        auth_basic_user_file /etc/nginx/users.passwd;
        auth_basic "join VPN or hit enter on this prompt:";

        limit_except GET {
            # block does not inherit the access limitations from above
            deny all;
        }

        location /uploading {
            limit_except GET POST {
               deny all;
            }
            proxy_pass http://unix:/run/backend.sock:/upload/;
        }
    }
}

Примеры запросов:

  1. Метод запросов DELETE вернет 405 (стандартная конфигурация должна добавить Allow заголовок, здесь опущен)
  2. GET от 203.0.113.0/24 всегда будет отвечать на основе /var/www/ html
  3. PROPFIND с 203.0.113.0/24 вернет 403
  4. при любом запросе с другого IP-адреса, если отсутствуют заголовки HBA, возвращается 401
  5. любой запрос POST, имеющий действительный HBA вне / доступный для записи, будет возвращен 403
  6. но внутри / доступный для записи запросы POST будут переданы на сервер
  7. Запросы PROPFIND с действующим HBA вернут 403
  8. любой другой метод, кроме DELETE, ответит на основании /var/www/ хорошо известного

Это тот случай, когда «если» не является злом. Согласно ссылке, опубликованной в вопросе , на 100% безопасно использовать возврат (и перезаписать... последний;) в теле if.

Другие вопросы по тегам