Использование 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/;
}
}
}
Примеры запросов:
- Метод запросов DELETE вернет 405
(стандартная конфигурация должна добавить
Allow
заголовок, здесь опущен) - GET от 203.0.113.0/24 всегда будет отвечать на основе /var/www/ html
- PROPFIND с 203.0.113.0/24 вернет 403
- при любом запросе с другого IP-адреса, если отсутствуют заголовки HBA, возвращается 401
- любой запрос POST, имеющий действительный HBA вне / доступный для записи, будет возвращен 403
- но внутри / доступный для записи запросы POST будут переданы на сервер
- Запросы PROPFIND с действующим HBA вернут 403
- любой другой метод, кроме DELETE, ответит на основании /var/www/ хорошо известного
Это тот случай, когда «если» не является злом. Согласно ссылке, опубликованной в вопросе , на 100% безопасно использовать возврат (и перезаписать... последний;) в теле if.