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, но я не уверен.