Django HTTPS с nginx в качестве обратного прокси. Проблемы с токенами CSRF

Я разработал приложение Django, которое запускается внутри контейнера docker. За пределами контейнера запущенный nginx выполняет обратную прокси-трансляцию запросов к этому приложению django. Django работает через WSGI с помощью gunicorn.

Общая настройка:

  • Я использую HTTP-сервер на 80-м порту, который обслуживает только перенаправление на HTTPS на 443-м порту. Никакие данные на этом порту не передаются.
  • Порт 443 настроен для HTTP/2 с SSL-шифрованием.
    • Путь /static обслуживается nginx для предоставления статических данных django.
    • Путь / настроен как прокси для экземпляра django:
    location / {
         proxy_set_header Host $http_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_pass http://127.0.0.1:8000; # This is the port the docker container with my django listens to
    }

Django (версия 5.1.3) сконфигурирован со следующими опциями:

# Production only settings
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_SSL_REDIRECT = False

Я установил значение SECURE_SSL_REDIRECT в false, так как у меня есть внутренняя проверка работоспособности сервера, которая обращается к приложению django на http://localhost:8000 и проверяет его состояние. Поскольку на этом маршруте нет HTTPS, принудительное SSL-перенаправление нарушит эту проверку. Я полагаюсь на строгую конфигурацию nginx, что внешний доступ никогда не может происходить через HTTP (без S). Конечно, порт 8000 заблокирован от интернета и разрешен только для соединений с localhost.

Первый вопрос: Является ли такой подход жизнеспособным для производства?

Второй вопрос: Я явно упомянул, что использую контейнер docker, потому что у меня есть друг, использующий то же приложение на своем сервере. Он использует тот же контейнер docker. Таким образом, различия в настройках django устраняются. Однако на его сервере установлена более старая версия nginx.

Он использует: nginx/1.14.2. Назовем это «старой установкой». Я использую: nginx/1.26.2. Назовем это «новой установкой»

На старой установке CSRF-токены не работают из-за неудачных проверок безопасности. В том числе

SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")

в конфигурации django решает эту проблему.

На новой установке с моей стороны в этом нет необходимости. Классический случай «Работает, но я не знаю почему». Я не могу понять, почему она работает на «новой установке». У кого-нибудь есть идеи, почему эта конфигурация показывает разное поведение на двух установках?

В настоящее время я не решаюсь просто включить SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https"), так как не понял суть проблемы. Согласно вики, я думаю, что это должно быть безопасно с вышеописанной конфигурацией прокси nginx, но я не уверен.

Вернуться на верх