Переменные в директивах без подстановки¶
Идентификатор проверки Gixy: non_expanding_variable
Многие директивы NGINX подставляют значения переменных, поэтому легко решить,
что так работают все. Значения map
могут содержать переменные. Значения
geo и
split_clients
не могут: NGINX сохраняет $binary_remote_addr как строку из 19 символов
$binary_remote_addr. nginx -t не выдаёт предупреждений.
Общая корзина ограничения запросов¶
Эта конфигурация выглядит как ограничение частоты для каждого клиента со списком исключений:
geo $limit_key {
default $binary_remote_addr; # сохраняется буквально!
127.0.0.1 "";
}
limit_req_zone $limit_key zone=dynamic:10m rate=5r/s;
Все клиенты вне списка исключений получают один и тот же ключ
$binary_remote_addr и делят одну корзину. Всплеск запросов одного
краулера исчерпывает лимит, и реальные посетители получают 503. Gixy
сообщает об этом с уровнем HIGH и указывает директиву limit_req_zone или
limit_conn_zone, использующую ключ.
Безопасная альтернатива¶
Пусть geo только классифицирует клиентов, а связанный map подставляет
переменную. Это шаблон списка исключений из
руководства NGINX по ограничению частоты:
geo $limit {
default 1;
127.0.0.1 0;
10.0.0.0/8 0;
}
map $limit $limit_key {
0 "";
1 $binary_remote_addr;
}
limit_req_zone $limit_key zone=dynamic:10m rate=5r/s;
Для split_clients используйте тот же подход: возвращайте буквальную метку и
сопоставляйте её со значением переменной в map.
Шаблоны, которые никогда не подставляются¶
Шаблоны location, server_name, rewrite и if компилируются один раз при
загрузке конфигурации, поэтому переменные в них не подставляются. Gixy
сообщает о них с уровнем MEDIUM:
set $admin admin;
# Префиксный location: совпадает только с буквальным URI "/$admin/"
location /$admin/ { deny all; }
# Регулярное выражение: "$" означает конец строки, поэтому "^/$admin/"
# никогда не совпадёт, и deny молча пропускается
location ~ ^/$admin/ { deny all; }
rewrite ^/$old/(.*)$ /new/$1 permanent; # никогда не срабатывает
if ($uri ~ $blocked) { return 403; } # регулярное выражение - текст "$blocked"
server_name $tenant.example.com; # совпадает с Host "$tenant.example.com"
Запишите значение явно или перенесите сравнение в map:
location ~ ^/admin/ { deny all; }
map $uri $blocked_uri {
default 0;
~^/private 1;
}
Знак доллара, экранированный как \$ или внутри класса символов вроде [$],
является обычным символом, и о нём не сообщается. server_name $hostname -
документированное специальное имя, и оно допускается.
URI в auth_request¶
auth_request отправляет подзапрос на URI ровно в том виде, в каком он
записан. При auth_request /auth/$host; подзапрос уходит на /auth/$host.
Если какой-либо location отвечает на этот URI статусом 2xx, авторизуется
каждый запрос, поэтому Gixy сообщает об этом с уровнем HIGH. Используйте
фиксированный URI и передавайте данные запроса в заголовках:
location / {
auth_request /auth;
}
location = /auth {
internal;
proxy_set_header X-Original-Host $host;
proxy_pass http://auth-backend;
}
Неподставленные переменные окружения¶
NGINX не читает переменные окружения в конфигурации. Имя вида ${UPPER_CASE},
которое не определено через set, map или другую директиву, почти всегда
является заполнителем шаблона, который не был обработан:
# Скопировано из шаблона Docker без запуска envsubst
proxy_pass http://${BACKEND_HOST}:8080;
Gixy сообщает об этом с уровнем MEDIUM. Обработайте шаблон через envsubst до
запуска NGINX. Официальный образ Docker делает это для
/etc/nginx/templates/*.template.
Пути без поддержки переменных¶
Эти директивы используют путь буквально и создают файлы или каталоги с $ в
имени. Gixy сообщает о них с уровнем LOW:
| Директива | Буквальный аргумент |
|---|---|
error_log |
путь к файлу |
client_body_temp_path, proxy_temp_path, fastcgi_temp_path, uwsgi_temp_path, scgi_temp_path |
каталог |
proxy_cache_path, fastcgi_cache_path, uwsgi_cache_path, scgi_cache_path |
каталог |
# Создаёт файл с именем "$host.error.log"
error_log /var/log/nginx/$host.error.log;
access_log поддерживает переменные, поэтому о нём не сообщается. Переменные
также подставляются в значениях map, в add_header, proxy_set_header,
root, alias, try_files, proxy_pass и в ключе limit_req_zone.
Ловите такие ошибки до продакшена
GetPageSpeed Amplify запускает Gixy по расписанию на каждом сервере NGINX и оповещает о новых находках и CVE, показывая их рядом с метриками. Настроить непрерывный мониторинг.