Корректна ли эта конфигурация nginx для работы с DNS-сервером Unbound?

Здравствуйте. Я ставлю Nginx перед Unbound для шифрования и управления профилями клиентов, а также предоставляю доступ к Unbound по ссылкам вида dns. domain. xyz/FgCKkdkf <br/> Ниже — моя конфигурация nginx для Unbound. Какие в ней есть проблемы с точки зрения безопасности и что можно улучшить? Конфигурация сейчас полностью рабочая. Дополнительно у меня есть скрипт, который генерирует HTML-страницу с возможностью скачать .mobileconfig для iOS и сгенерированными DoH-ссылками для других клиентов; эта страница автоматически удаляется через 10 минут. <br/>
  • 20 февраля 2026 г. 23:02
Ответы на вопрос 1
Короткий ответ — конфигурация может быть «работающей», но без просмотра конкретного конфига трудно сказать, нет ли у вас пробелов. Ниже — перечень типичных рисков и улучшений для ситуации «Nginx перед Unbound (DoH/HTTP) + временные ссылки/.mobileconfig», а также пример безопасной конфигурации и рекомендации, что ещё проверить. Если пришлёте ваш nginx.conf — я укажу на конкретные проблемы.

1) Общие принципы безопасности (обязательно)
- TLS
  - Разрешать только TLS 1.2+ и предпочесть TLS 1.3: ssl_protocols TLSv1.2 TLSv1.3;
  - Использовать современные cipher suites (рекомендации Mozilla Modern/Intermediate). Пример для 1.2: ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:...'; включить PFS (ECDHE).
  - Включить ssl_prefer_server_ciphers on (для TLS1.2), включить ssl_session_cache, настроить session ticket/ключи и их ротацию; можно выключить session tickets (ssl_session_tickets off) если не управляете ключами.
  - Включить OCSP stapling: ssl_stapling on; ssl_stapling_verify on; ssl_trusted_certificate /path/to/fullchain.pem; и настроить резолвер для stapling.
- HSTS и другие заголовки
  - Добавить Strict-Transport-Security (HSTS) с разумным max-age (например 6–12 недель при первом включении, затем больше) и includeSubDomains по необходимости.
  - Security headers: X-Frame-Options DENY, X-Content-Type-Options nosniff, Referrer-Policy no-referrer (особенно если токены в URL), Content-Security-Policy по необходимости.
- Утечка токенов
  - Токены в URL могут утекать через Referer / логи / прокси-кэши. Установите Referrer-Policy: no-referrer и Cache-Control: no-store, no-cache для ответов, чтобы минимизировать риск.
  - Логи: если токен критичен, подумайте о том, чтобы не записывать полный URI в access_log (или маскировать токен). Nginx по умолчанию логирует $request_uri.
- Кеширование
  - По умолчанию DoH-ответы не должны кэшироваться промежуточными HTTP-кэшеми. Добавьте Cache-Control: private, no-store или no-cache, Pragma: no-cache, и Vary при необходимости.
- Контроль доступа и лимиты
  - Ограничьте частоту запросов: limit_req_zone + limit_req (rate limiting) и limit_conn если нужно.
  - Ограничьте максимальный размер тела и таймауты: client_max_body_size, client_body_timeout, client_header_timeout, send_timeout.
  - Ограничьте число одновременных соединений к upstream: limit_conn_zone/limit_conn.
- Прокси/передача заголовков
  - Передавайте минимально необходимые заголовки: proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme.
  - Для бинарных POST (application/dns-message) убедитесь, что Nginx не портит тело: proxy_request_buffering off (если хотите стримить), proxy_buffering off, proxy_http_version 1.1 и передача Content-Length.
- Контент .mobileconfig и HTML-страница
  - Отдавайте .mobileconfig только по HTTPS, Content-Type application/x-apple-aspen-config, Content-Disposition: attachment; filename=... .
  - Ограничьте срок действия ссылок на серверной стороне (не только удалением HTML): токены должны быть действительны/проверяться сервером и истекать.
  - Установите заголовки безопасности (CSP, X-Frame-Options и т. п.) и Cache-Control: no-store для страниц со ссылками/токенами.
- Защита от сканирования/брутфорса
  - Мониторьте и ставьте rate limit, fail2ban по логам, блокируйте подозрительные IP.
- Серверные заголовки
  - server_tokens off; скрывайте версии.
- Контроль содержания ответов
  - Убедитесь, что Nginx не модифицирует DNS-ответы и не декодирует бинар. Для DoH важно передавать заголовки Content-Type: application/dns-message и точно пробрасывать тело.

2) Конкретные директивы nginx, на которые обратить внимание
- ssl_protocols TLSv1.2 TLSv1.3;
- ssl_ciphers (взять из актуального Mozilla config);
- ssl_prefer_server_ciphers on;
- ssl_session_cache shared:SSL:10m;
- ssl_session_tickets off (или управлять ключами);
- ssl_stapling on; ssl_stapling_verify on; resolver 1.1.1.1 valid=30s;
- proxy_buffering off;
- proxy_request_buffering off;  # если важно стримить бинарный body
- proxy_http_version 1.1;
- proxy_set_header Connection "";
- client_max_body_size 64k;  # DoH ограничен, настройте по потребностям
- client_body_timeout 10s; client_header_timeout 10s; send_timeout 10s;
- limit_req_zone $binary_remote_addr zone=doh_limit:10m rate=10r/s;
- add_header Strict-Transport-Security "max-age=...; includeSubDomains; preload" always;
- add_header Referrer-Policy "no-referrer" always;
- add_header X-Content-Type-Options "nosniff" always;
- add_header X-Frame-Options "DENY" always;

3) Минимальная примерная конфигурация для DoH (упрощённо)
(ниже — примерный фрагмент; адаптируйте пути/порт upstream)

server {
    listen 443 ssl http2;
    server_name dns.example.tld;

    ssl_certificate /etc/letsencrypt/live/dns.example.tld/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/dns.example.tld/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:...'; # взять из современного профиля
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_tickets off;
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 1.1.1.1 8.8.8.8 valid=30s;

    server_tokens off;

    # security headers
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
    add_header X-Frame-Options "DENY" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "no-referrer" always;

    # rate limit
    limit_req_zone $binary_remote_addr zone=doh_zone:10m rate=10r/s;

    location ~ ^/([A-Za-z0-9_-]{8,})$ {
        # path-based token: прокси на локальный DoH Unbound
        limit_req zone=doh_zone burst=20 nodelay;

        # предотвратить кэширование токена/ответа
        add_header Cache-Control "no-store, no-cache, must-revalidate, max-age=0" always;
        add_header Pragma "no-cache" always;

        proxy_pass http://127.0.0.1:8053/dns-query;  # пример upstream unbound
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_http_version 1.1;
        proxy_buffering off;
        proxy_request_buffering off;
        proxy_set_header Connection "";
        client_max_body_size 64k;
    }

    # static files (.mobileconfig etc.) с безопасными заголовками
    location /download/ {
        root /var/www/dns;
        autoindex off;
        # отдавать как приложение/attachment
    }
}

4) Особенности, связанные с вашим рабочим процессом (временные страницы и .mobileconfig)
- Удаление HTML через 10 минут — это OK, но не полагайтесь только на удаление файла: серверная логика должна инвалидировать токен (в БД или в памяти) и не допускать повторного использования.
- Токен в ссылке: лучше передавать токен в заголовке (Authorization: Bearer TOKEN) или в теле POST, чтобы он не попал в Referer/логи. Если это неудобно (например, клиент iOS ждёт URL), обязательно делайте короткий TTL и Referrer-Policy: no-referrer.
- При генерации .mobileconfig — подпишете/проверьте содержимое и не вставляйте приватные ключи в конфиг, если это не нужно.

5) Логи и приватность
- Если вы хотите анонимность клиентов — не передавайте X-Real-IP в Unbound и не логируйте полные URI. Если хотите видеть реальные IP — передавайте и храните логи безопасно.
- Маскирование токенов в логах: можно писать отдельный формат access_log без $request_uri, или писать фильтр логов, чтобы не оставлять секреты.

6) Мониторинг и реагирование
- Настройте мониторинг числа запросов, latency, ошибок 4xx/5xx, чтобы быстро заметить злоупотребления.
- Ведите ротацию сертификатов/ключей и резервирование.

7) Что проверить у вас (список для самой быстрой проверки)
- ssl_protocols и ssl_ciphers — безопасны ли они?
- ssl_stapling включён и работает?
- Referrer-Policy установлен?
- Cache-Control для DoH-ответов — no-store?
- Таймауты и лимиты установлены?
- proxy_request_buffering/proxy_buffering используются корректно для бинарного трафика?
- Токены действительно верифицируются серверной логикой и удаляются/истекают на сервере?
- Логи не сохраняют секреты (или вы согласны с этим риском)?

Если пришлёте ваш конкретный конфиг — я просмотрю и укажу на конкретные директивы, которые стоит поправить, и дам готовый исправленный конфиг.
Похожие вопросы