| 1 |
worker_processes 1; |
| 2 |
|
| 3 |
events { |
| 4 |
worker_connections 128; |
| 5 |
} |
| 6 |
|
| 7 |
http { |
| 8 |
missing_client_max_body
client_max_body_size не задан — по умолчанию 1MB, возможен DoS или отказ в загрузке файлов
Check Проверка отсутствия client_max_body_size
Solution Явно задайте client_max_body_size в http-блоке: client_max_body_size 10m;
Example # Задайте лимит в http-блоке:
http {
client_max_body_size 10m; # под ваши нужды
...
}
# --- Нет client_max_body_size --- |
| 9 |
|
| 10 |
ssl_session_tickets_enabled
ssl_session_tickets не отключены в SSL server-блоке 'secure.example.com'
Check Проверка ssl_session_tickets off
Solution Добавьте ssl_session_tickets off; — session tickets нарушают forward secrecy при компрометации ticket key.
# --- Устаревшие SSL-протоколы --- |
| 11 |
ssl_protocols_weak
ssl_protocols содержит устаревшие протоколы: TLSv1 TLSv1.1 TLSv1.2
Check Проверка устаревших SSL-протоколов
Solution Отключите устаревшие протоколы TLS.
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; |
| 12 |
ssl_ciphers_weak
ssl_ciphers содержит слабые шифры: DES-CBC3-SHA:RC4-SHA:AES128-SHA
Check Проверка слабых SSL-шифров
Solution Используйте современные шифры.
ssl_ciphers DES-CBC3-SHA:RC4-SHA:AES128-SHA; |
| 13 |
|
| 14 |
# --- Нет merge_slashes --- |
| 15 |
merge_slashes off; |
| 16 |
|
| 17 |
# --- error_log отключён --- |
| 18 |
error_log /dev/null; |
| 19 |
|
| 20 |
# --- Внешний резолвер --- |
| 21 |
resolver_external
8.8.8.8
Check Проверка внешнего DNS resolver
Solution Используйте локальный resolver (127.0.0.1) вместо внешних DNS-серверов.
Example # Используйте внутренний DNS:
resolver 127.0.0.1 valid=30s;
# Вместо внешнего: 8.8.8.8 или 1.1.1.1
resolver 8.8.8.8; |
| 22 |
|
| 23 |
# --- set_real_ip_from любой --- |
| 24 |
real_ip_from_any
set_real_ip_from 0.0.0.0/0 — доверяет всем IP, возможна подделка
Check Проверка set_real_ip_from 0.0.0.0/0 (подделка IP)
Solution Укажите конкретные IP/сети доверенных прокси вместо 0.0.0.0/0.
Example # Укажите конкретные IP прокси:
set_real_ip_from 10.0.0.0/8;
set_real_ip_from 172.16.0.0/12;
real_ip_header X-Forwarded-For;
# НЕ используйте: set_real_ip_from 0.0.0.0/0;
set_real_ip_from 0.0.0.0/0; |
| 25 |
real_ip_header X-Forwarded-For; |
| 26 |
|
| 27 |
# ========================================= |
| 28 |
no_limit_req_conn
server без limit_req/limit_conn в блоке 'None'
Check Проверка наличия лимитов запросов/соединений
Solution Добавьте limit_req/limit_conn для защиты от DDoS.
no_limit_req_conn
server без limit_req/limit_conn в блоке 'None'
Check Проверка наличия лимитов запросов/соединений
Solution Добавьте limit_req/limit_conn для защиты от DDoS.
no_limit_req_conn
server без limit_req/limit_conn в блоке 'None'
Check Проверка наличия лимитов запросов/соединений
Solution Добавьте limit_req/limit_conn для защиты от DDoS.
default_server_flag
listen *:80 — 2 server-блока без default_server
Check Проверка отсутствия default_server
Solution Добавьте default_server к одному из server-блоков на этом адресе:порту.
missing_https_redirect
server example.com: listen 80 без redirect на HTTPS — возможен downgrade и перехват cookie
Check Проверка отсутствия HTTPS redirect для HTTP
Solution Добавьте return 301 https://$host$request_uri; в server { listen 80; }
Example # Redirect HTTP → HTTPS:
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}
server_tokens_not_hidden
Версия Server не скрыта/изменена в блоке 'http '
Check Проверка скрытия версии Server
Solution Скройте или измените заголовок Server (server_tokens off; или server_tokens build;) для уменьшения поверхности атаки.
# Сервер без default_server, без HTTPS redirect |
| 29 |
# ========================================= |
| 30 |
server { |
| 31 |
listen 80; |
| 32 |
dotfile_exposed
server example.com www.example.com: нет блокировки dotfiles (/.env, /.git, /.htpasswd и др.)
Check Проверка блокировки dotfiles (/.env, /.git и др.)
Solution Добавьте: location ~ /\.(?!well-known) { deny all; } для блокировки /.env, /.git и др.
Example # Заблокируйте все dotfiles:
location ~ /\.(?!well-known) {
deny all;
access_log off;
log_not_found off;
}
server_name example.com www.example.com; |
| 33 |
|
| 34 |
autoindex_on
autoindex on в блоке server
Check Проверка autoindex on
Solution Отключите autoindex, если не требуется публикация файлов.
# --- autoindex включён --- |
| 35 |
autoindex on; |
| 36 |
|
| 37 |
git_exposed
Возможен доступ к .git в server-блоке 'example.com www.example.com'
Check Проверка доступа к .git
Solution Добавьте 'location ~ /\.git/ { deny all; }' для блокировки доступа к репозиторию.
git_exposed
Возможен доступ к .git в server-блоке 'secure.example.com'
Check Проверка доступа к .git
Solution Добавьте 'location ~ /\.git/ { deny all; }' для блокировки доступа к репозиторию.
git_exposed
Возможен доступ к .git в server-блоке 'example.com'
Check Проверка доступа к .git
Solution Добавьте 'location ~ /\.git/ { deny all; }' для блокировки доступа к репозиторию.
# --- .git открыт --- |
| 38 |
dotfile_exposed
server secure.example.com: нет блокировки dotfiles (/.env, /.git, /.htpasswd и др.)
Check Проверка блокировки dotfiles (/.env, /.git и др.)
Solution Добавьте: location ~ /\.(?!well-known) { deny all; } для блокировки /.env, /.git и др.
Example # Заблокируйте все dotfiles:
location ~ /\.(?!well-known) {
deny all;
access_log off;
log_not_found off;
}
dotfile_exposed
server example.com: нет блокировки dotfiles (/.env, /.git, /.htpasswd и др.)
Check Проверка блокировки dotfiles (/.env, /.git и др.)
Solution Добавьте: location ~ /\.(?!well-known) { deny all; } для блокировки /.env, /.git и др.
Example # Заблокируйте все dotfiles:
location ~ /\.(?!well-known) {
deny all;
access_log off;
log_not_found off;
}
backup_files_exposed
Нет блокировки backup-файлов (.bak, .sql, .tar, .swp и др.) — добавьте: location ~* \.(bak|sql|tar|gz|swp|old)$ { deny all; }
Check Проверка блокировки backup-файлов (.bak, .sql, .tar и др.)
Solution Добавьте: location ~* \.(bak|sql|tar|gz|swp|old|orig|dump)$ { deny all; }
Example # Заблокируйте backup-файлы:
location ~* \.(bak|sql|tar|gz|zip|swp|old|orig|dump|log)$ {
deny all;
access_log off;
}
# (нет блокировки location ~ /\.git) |
| 39 |
|
| 40 |
# --- dotfiles открыты (.env, .htpasswd) --- |
| 41 |
# (нет location ~ /\.) |
| 42 |
|
| 43 |
# --- backup-файлы открыты --- |
| 44 |
# (нет location ~* \.(bak|sql|tar|gz|swp)) |
| 45 |
|
| 46 |
missing_security_header
отсутствует security header: Strict-Transport-Security
Check Проверка наличия заголовков безопасности
Solution Добавьте security-заголовок.
missing_security_header
отсутствует security header: Referrer-Policy
Check Проверка наличия заголовков безопасности
Solution Добавьте security-заголовок.
missing_security_header
отсутствует security header: Content-Security-Policy
Check Проверка наличия заголовков безопасности
Solution Добавьте security-заголовок.
# --- Нет security-заголовков --- |
| 47 |
# (нет X-Frame-Options, X-Content-Type-Options и т.д.) |
| 48 |
|
| 49 |
# --- Дублирующиеся директивы --- |
| 50 |
root /var/www/html; |
| 51 |
root /var/www/site; |
| 52 |
|
| 53 |
proxy_ip_disclosure
Блок с proxy_pass не защищен от раскрытия внутренних IP: 'location /'
Check Проверка раскрытия внутренних IP-адресов
Solution Добавьте 'proxy_redirect off;' или 'proxy_redirect default;' в блоки с proxy_pass для предотвращения раскрытия внутренних IP-адресов.
proxy_ip_disclosure
Блок с proxy_pass не защищен от раскрытия внутренних IP: 'location /api/'
Check Проверка раскрытия внутренних IP-адресов
Solution Добавьте 'proxy_redirect off;' или 'proxy_redirect default;' в блоки с proxy_pass для предотвращения раскрытия внутренних IP-адресов.
proxy_ip_disclosure
Блок с proxy_pass не защищен от раскрытия внутренних IP: 'location /internal'
Check Проверка раскрытия внутренних IP-адресов
Solution Добавьте 'proxy_redirect off;' или 'proxy_redirect default;' в блоки с proxy_pass для предотвращения раскрытия внутренних IP-адресов.
proxy_ip_disclosure
Блок с proxy_pass не защищен от раскрытия внутренних IP: 'location /admin-panel'
Check Проверка раскрытия внутренних IP-адресов
Solution Добавьте 'proxy_redirect off;' или 'proxy_redirect default;' в блоки с proxy_pass для предотвращения раскрытия внутренних IP-адресов.
proxy_ip_disclosure
Блок с proxy_pass не защищен от раскрытия внутренних IP: 'location /metrics'
Check Проверка раскрытия внутренних IP-адресов
Solution Добавьте 'proxy_redirect off;' или 'proxy_redirect default;' в блоки с proxy_pass для предотвращения раскрытия внутренних IP-адресов.
proxy_ip_disclosure
Блок с proxy_pass не защищен от раскрытия внутренних IP: 'location /'
Check Проверка раскрытия внутренних IP-адресов
Solution Добавьте 'proxy_redirect off;' или 'proxy_redirect default;' в блоки с proxy_pass для предотвращения раскрытия внутренних IP-адресов.
proxy_ip_disclosure
Блок с proxy_pass не защищен от раскрытия внутренних IP: 'location /api/'
Check Проверка раскрытия внутренних IP-адресов
Solution Добавьте 'proxy_redirect off;' или 'proxy_redirect default;' в блоки с proxy_pass для предотвращения раскрытия внутренних IP-адресов.
proxy_pass_no_scheme
proxy_pass без схемы: backend:3000
Check Проверка proxy_pass на отсутствие схемы
Solution Добавьте http:// или https:// в proxy_pass.
# --- proxy_pass без схемы --- |
| 54 |
location / { |
| 55 |
proxy_pass backend:3000; |
| 56 |
http_splitting
proxy_set_header … $http_host (может содержать \n/\r)
Check Проверка HTTP Response Splitting
Solution Не используйте $request_uri/$arg_*/$http_* в заголовках и редиректах напрямую — применяйте $uri или sanitize-переменную.
Example # Используйте статичный URI или $uri:
return 301 https://example.com$uri;
# НЕ используйте $request_uri напрямую
host_spoofing
proxy_set_header Host $http_host
Check Проверка подделки Host-заголовка
Solution Замените $http_host на $host в proxy_set_header Host.
Example # Явно задайте имя сервера:
server_name example.com;
# НЕ используйте:
# server_name _; # или не задавайте
proxy_set_header Host "var">$http_host; # host_spoofing |
| 57 |
} |
| 58 |
|
| 59 |
# --- SSRF через переменную в proxy_pass --- |
| 60 |
add_header_redefinition
location /api/ — теряет security-заголовки: x-content-type-options, x-frame-options
Check Проверка сброса security-заголовков в дочерних блоках
Solution Повторите нужные заголовки в дочернем блоке или используйте add_header_inherit merge (nginx 1.29.3+).
location /api/ { |
| 61 |
ssrf
http://$arg_target (переменная $arg_target в хосте/схеме)
Check Проверка SSRF через proxy_pass
Solution Замените переменную в host/scheme на фиксированное значение или используйте map с белым списком.
Example # Запрещайте внутренние адреса:
proxy_pass http://backend$uri;
# НЕ используйте:
# proxy_pass http://$host$request_uri;
http_splitting
proxy_pass … $arg_target (может содержать \n/\r)
Check Проверка HTTP Response Splitting
Solution Не используйте $request_uri/$arg_*/$http_* в заголовках и редиректах напрямую — применяйте $uri или sanitize-переменную.
Example # Используйте статичный URI или $uri:
return 301 https://example.com$uri;
# НЕ используйте $request_uri напрямую
proxy_pass http://"var">$arg_target; |
| 62 |
} |
| 63 |
|
| 64 |
# --- HTTP Response Splitting --- |
| 65 |
location /redirect { |
| 66 |
http_splitting
return … $request_uri (может содержать \n/\r)
Check Проверка HTTP Response Splitting
Solution Не используйте $request_uri/$arg_*/$http_* в заголовках и редиректах напрямую — применяйте $uri или sanitize-переменную.
Example # Используйте статичный URI или $uri:
return 301 https://example.com$uri;
# НЕ используйте $request_uri напрямую
return 302 https://example.com"var">$request_uri; |
| 67 |
http_splitting
add_header … $http_referer (может содержать \n/\r)
Check Проверка HTTP Response Splitting
Solution Не используйте $request_uri/$arg_*/$http_* в заголовках и редиректах напрямую — применяйте $uri или sanitize-переменную.
Example # Используйте статичный URI или $uri:
return 301 https://example.com$uri;
# НЕ используйте $request_uri напрямую
add_header X-Custom "var">$http_referer; |
| 68 |
} |
| 69 |
|
| 70 |
# --- alias traversal --- |
| 71 |
alias_traversal
location /files → alias /var/www/uploads (location без завершающего /)
Check Проверка path traversal через alias
Solution Добавьте завершающий / как в location, так и в alias: location /files/ { alias /data/files/; }
Example # Добавьте слеш в конце location:
location /static/ {
alias /var/www/static/;
}
# location /static без / — уязвимость!
location /files { |
| 72 |
alias /var/www/uploads; |
| 73 |
} |
| 74 |
|
| 75 |
# --- Конфликтующие location --- |
| 76 |
alias_traversal
location /static → alias /var/www/assets/ (location без завершающего /)
Check Проверка path traversal через alias
Solution Добавьте завершающий / как в location, так и в alias: location /files/ { alias /data/files/; }
Example # Добавьте слеш в конце location:
location /static/ {
alias /var/www/static/;
}
# location /static без / — уязвимость!
location_conflict
server: None location: /static ↔ /static
Check Проверка конфликтов location
Solution Возможное пересечение location. Это не всегда ошибка: порядок и типы location могут быть корректны. Проверьте, что порядок и типы location соответствуют вашим ожиданиям. Если всё ок — игнорируйте предупреждение.
location /static { |
| 77 |
root /var/www; |
| 78 |
} |
| 79 |
location /static { |
| 80 |
alias /var/www/assets/; |
| 81 |
} |
| 82 |
|
| 83 |
# --- allow без deny all --- |
| 84 |
location /internal { |
| 85 |
allow 10.0.0.0/8; |
| 86 |
allow 192.168.0.0/16; |
| 87 |
proxy_pass http://backend; |
| 88 |
} |
| 89 |
|
| 90 |
# --- return обходит allow/deny --- |
| 91 |
return_bypasses_allow_deny
location /admin
Check Проверка обхода allow/deny через return
Solution Перенесите return в named location или используйте try_files; allow/deny не защищают от return в том же блоке.
location /admin { |
| 92 |
allow 10.0.0.0/8; |
| 93 |
deny all; |
| 94 |
return 200 "admin panel"; |
| 95 |
} |
| 96 |
|
| 97 |
# --- admin панель без auth --- |
| 98 |
location /admin-panel { |
| 99 |
proxy_pass http://backend:8080; |
| 100 |
} |
| 101 |
|
| 102 |
# --- metrics открыты --- |
| 103 |
metrics_exposed
location /metrics доступен без ограничений — добавьте allow/deny или auth_basic
Check Проверка открытых metrics/debug endpoints
Solution Ограничьте доступ к metrics/debug endpoint: добавьте allow 127.0.0.1; deny all; или auth_basic.
Example # Ограничьте доступ к metrics:
location /metrics {
allow 127.0.0.1;
allow 10.0.0.0/8;
deny all;
proxy_pass http://localhost:9090;
}
metrics_exposed
location /nginx_status доступен без ограничений — добавьте allow/deny или auth_basic
Check Проверка открытых metrics/debug endpoints
Solution Ограничьте доступ к metrics/debug endpoint: добавьте allow 127.0.0.1; deny all; или auth_basic.
Example # Ограничьте доступ к metrics:
location /metrics {
allow 127.0.0.1;
allow 10.0.0.0/8;
deny all;
proxy_pass http://localhost:9090;
}
location /metrics { |
| 104 |
proxy_pass http://prometheus:9090; |
| 105 |
} |
| 106 |
|
| 107 |
status_page_exposed
stub_status в блоке location /nginx_status — нет allow/deny all
Check Проверка открытого stub_status
Solution Ограничьте доступ к stub_status: добавьте allow 127.0.0.1; deny all;
location /nginx_status { |
| 108 |
stub_status; |
| 109 |
allow_without_deny
location /internal — нет deny all
Check Проверка allow без deny all
Solution Добавьте deny all; после директив allow.
Example # Всегда добавляйте deny all после allow:
allow 192.168.1.0/24;
allow 10.0.0.0/8;
deny all;
# нет allow/deny |
| 110 |
} |
| 111 |
|
| 112 |
php_fastcgi_unsafe
location ~ \.php$: fastcgi_pass без try_files $uri =404 — возможен file upload bypass (file.php.jpg)
Check Проверка PHP FastCGI без try_files (file upload bypass)
Solution Добавьте try_files $uri =404; перед fastcgi_pass для блокировки file upload bypass.
Example # Добавьте try_files перед fastcgi_pass:
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass php-fpm;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# --- PHP FastCGI без try_files --- |
| 113 |
location ~ \.php$ { |
| 114 |
fastcgi_ip_disclosure
Блок с fastcgi_pass может раскрывать информацию: 'location ~ \.php$'
Check Проверка раскрытия информации через FastCGI
Solution Добавьте 'fastcgi_hide_header X-Powered-By;' и/или 'fastcgi_hide_header Location;' в блоки с fastcgi_pass для предотвращения раскрытия информации.
fastcgi_pass unix:/run/php/php-fpm.sock; |
| 115 |
fastcgi_param SCRIPT_FILENAME "var">$document_root"var">$fastcgi_script_name; |
| 116 |
include fastcgi_params; |
| 117 |
} |
| 118 |
|
| 119 |
if_block
директива if внутри блока location
Check Проверка использования if в location
Solution Избегайте if внутри location, используйте map/try_files.
if_block
директива if внутри блока location
Check Проверка использования if в location
Solution Избегайте if внутри location, используйте map/try_files.
# --- if внутри location --- |
| 120 |
location /old { |
| 121 |
if ("var">$request_uri ~* "^/old/(.*)$") { |
| 122 |
return 301 /new/"var">$1; |
| 123 |
} |
| 124 |
} |
| 125 |
|
| 126 |
# --- Пустой блок --- |
| 127 |
empty_block
location /empty
Check Проверка пустых блоков
Solution Удалите или заполните пустой блок.
dead_location
server: None location: /empty
Check Проверка 'мертвых' location-ов
Solution Удалите неиспользуемый location или используйте его.
location /empty { |
| 128 |
} |
| 129 |
|
| 130 |
# --- rewrite без флага --- |
| 131 |
rewrite_no_flag
^/blog/(.*)$ /articles/$1
Check Проверка rewrite-правил без флагов
Solution Добавьте last/break/redirect/permanent к rewrite.
rewrite ^/blog/(.*)$ /articles/"var">$1; |
| 132 |
|
| 133 |
# --- rewrite цикл --- |
| 134 |
rewrite ^/loop/(.*)$ /loop/"var">$1 last; |
| 135 |
|
| 136 |
# --- Переменная в root --- |
| 137 |
location /dynamic { |
| 138 |
root_alias_with_variable
Директива 'root' использует переменную: /var/www/$host
Check Проверка 'root'/'alias' на использование переменных
Solution Использование переменных в директивах 'root' или 'alias' может привести к уязвимостям обхода каталога (Path Traversal).
root /var/www/"var">$host; |
| 139 |
} |
| 140 |
|
| 141 |
listen_servername_conflict
server1: None server2: None listen: 80 server_name: example.com
Check Проверка конфликтов listen/server_name
Solution Измените listen/server_name для устранения конфликта.
# --- valid_referers с none --- |
| 142 |
location /images/ { |
| 143 |
valid_referers_none
none server_names
Check Проверка valid_referers none
Solution Уберите none из valid_referers или используйте другой механизм защиты.
Example # Уберите none или добавьте реальные referer:
valid_referers server_names example.com;
if ($invalid_referer) { return 403; }
valid_referers none server_names; |
| 144 |
if ("var">$invalid_referer) { |
| 145 |
return 403; |
| 146 |
} |
| 147 |
root /var/www; |
| 148 |
} |
| 149 |
} |
| 150 |
|
| 151 |
# ========================================= |
| 152 |
# SSL-сервер с проблемами |
| 153 |
# ========================================= |
| 154 |
server { |
| 155 |
listen_443_no_ssl
listen без ssl: 443
Check Проверка listen 443 без ssl
Solution Добавьте ssl к listen 443.
listen_443_no_http2
listen 443 без http2: 443
Check Проверка listen 443 без http2
Solution Добавьте http2 к listen 443 для производительности.
listen 443; # нет ssl |
| 156 |
server_name secure.example.com; |
| 157 |
|
| 158 |
ssl_certificate /etc/ssl/certs/example.com.pem; |
| 159 |
ssl_certificate_key /etc/ssl/private/example.com.key; |
| 160 |
missing_ssl_dhparam
Отсутствует 'ssl_dhparam' в SSL server-блоке ''
Check Проверка наличия ssl_dhparam
Solution Укажите сильные параметры Диффи-Хеллмана (ssl_dhparam) для защиты от атак.
# --- Нет ssl_dhparam --- |
| 161 |
missing_ssl_stapling
Отсутствует 'ssl_stapling on' в SSL server-блоке ''
Check Проверка OCSP Stapling
Solution Включите OCSP Stapling (ssl_stapling on) для улучшения производительности и приватности TLS.
# --- Нет ssl_stapling --- |
| 162 |
# --- Нет ssl_trusted_certificate --- |
| 163 |
|
| 164 |
# --- Нет limit_req/limit_conn --- |
| 165 |
|
| 166 |
location / { |
| 167 |
proxy_pass http://backend:3000; |
| 168 |
# --- нет proxy_redirect (IP disclosure) --- |
| 169 |
} |
| 170 |
|
| 171 |
# --- add_header переопределение --- |
| 172 |
add_header X-Frame-Options DENY; |
| 173 |
add_header X-Content-Type-Options nosniff; |
| 174 |
|
| 175 |
location /api/ { |
| 176 |
# заголовки из parent-блока потеряны |
| 177 |
add_header X-Api-Version "1.0"; |
| 178 |
proxy_pass http://backend:3000; |
| 179 |
} |
| 180 |
} |
| 181 |
|
| 182 |
# ========================================= |
| 183 |
# Конфликт listen/server_name |
| 184 |
# ========================================= |
| 185 |
server { |
| 186 |
listen 80; |
| 187 |
server_name example.com; |
| 188 |
|
| 189 |
location / { |
| 190 |
return 200 "duplicate"; |
| 191 |
} |
| 192 |
} |
| 193 |
|
| 194 |
# --- upstream для stale DNS (без resolver + без переменной) --- |
| 195 |
upstream backend { |
| 196 |
server backend-host.internal.company.com:3000; |
| 197 |
} |
| 198 |
} |