Как развернуть сайт только для HTTPS, с Django / nginx? - PullRequest
38 голосов
/ 16 ноября 2011

Мой оригинальный вопрос был о том, как включить HTTPS для страницы входа в Django , и единственный ответ, рекомендованный, чтобы я - сделал весь сайт только HTTPS .

Учитывая, что я использую Django 1.3 и nginx, как правильно сделать сайт только для HTTPS?

В одном ответе упоминалось решение промежуточного программного обеспечения , но была оговорка:

Django не может выполнить перенаправление SSL при сохранении данных POST. Пожалуйста, структурируйте свои представления так, чтобы перенаправления происходили только во время GET.

В вопросе об ошибке сервера о перезаписи nginx в https также упоминались проблемы с потерей данных POST, и я недостаточно знаком с nginx, чтобы определить, насколько хорошо работает решение.

И EFF рекомендует использовать только HTTPS , отмечает, что:

Приложение должно установить атрибут Secure в cookie, когда устанавливая это. Этот атрибут инструктирует браузер отправлять куки только по защищенному (HTTPS) транспорту, никогда не является небезопасным (HTTP).

Имеют ли приложения, такие как Django-auth, возможность устанавливать cookie-файлы как безопасные? Или я должен написать больше промежуточного программного обеспечения?

Итак, каков наилучший способ настроить комбинацию Django / nginx для реализации только HTTPS, с точки зрения:

  • безопасность
  • сохранение данных POST
  • куки-файлы обрабатываются правильно
  • взаимодействие с другими приложениями Django (например, Django-auth), работает нормально
  • любые другие проблемы, о которых я не знаю:)

Редактировать - еще одна проблема, которую я только что обнаружил при тестировании нескольких браузеров. Скажем, у меня есть URL https://mysite.com/search/, который имеет форму / кнопку поиска. Я нажимаю кнопку, обрабатываю форму в Django как обычно и выполняю Django HttpResponseRedirect до http://mysite.com/search?results="foo". Nginx перенаправляет это на https://mysite.com/search?results="foo", по желанию.

Однако - Opera имеет видимую вспышку , когда происходит перенаправление. И это происходит при каждом поиске, даже по одному и тому же поисковому запросу (я думаю, что https действительно не кэшируется :) Хуже того, когда я тестирую его в IE, я сначала получаю сообщение:

Вы собираетесь перенаправиться на небезопасное соединение - продолжить?

После нажатия «да» сразу же следует:

Вы собираетесь просматривать страницы через безопасное соединение - продолжить?

Хотя второе предупреждение IE имеет возможность отключить его - предупреждение first нет, поэтому каждый раз, когда кто-то выполняет поиск и перенаправляется на страницу результатов, он получает по крайней мере одно предупреждение .

Ответы [ 3 ]

52 голосов
/ 28 октября 2013

Для второй части ответа Джона С. и Django 1.4 + ...

Вместо расширения HttpResponseRedirect вы можете изменить request.scheme на https.Поскольку Django находится за обратным прокси-сервером Nginx, он не знает, что исходный запрос был безопасным.

В настройках Django установите значение SECURE_PROXY_SSL_HEADER :

SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

Затем вам нужно Nginx, чтобы установить пользовательский заголовок в обратном прокси.В настройках сайта Nginx:

location / {
    # ... 
    proxy_set_header X-Forwarded-Proto $scheme;
}

Таким образом request.scheme == 'https' и request.is_secure() возвращает True.request.build_absolute_uri() возвращает https://... и так далее ...

20 голосов
/ 18 ноября 2011

Вот решение, которое я разработал до сих пор.Есть две части: настройка nginx и написание кода для Django.Часть nginx обрабатывает внешние запросы, перенаправляя http страницы на https, а код Django обрабатывает внутреннюю генерацию URL с префиксом http.(По крайней мере, те, которые являются результатом HttpResponseRedirect()).В совокупности это, кажется, работает хорошо - насколько я могу судить, клиентский браузер никогда не видит страницу http, которую пользователи не вводили сами.

Часть первая, конфигурация nginx

# nginx.conf
# Redirects any requests on port 80 (http) to https:
server {
    listen       80;
    server_name  www.mysite.com mysite.com;
    rewrite ^ https://mysite.com$request_uri? permanent;
#    rewrite ^ https://mysite.com$uri permanent; # also works
}
# django pass-thru via uWSGI, only from https requests:
server {
    listen       443;
    ssl          on;
    ssl_certificate        /etc/ssl/certs/mysite.com.chain.crt;
    ssl_certificate_key    /etc/ssl/private/mysite.com.key;

    server_name  mysite.com;
    location / {
        uwsgi_pass 127.0.0.1:8088;
        include uwsgi_params;
    }
}

Часть вторая A, различные настройки безопасного cookie, из settings.py

SERVER_TYPE = "DEV"
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True # в настоящее время только в ветви Dev в Django.
SESS_EX_EXS_EX__S_SEX_EX__S_S_SEX_EXTrue

Часть вторая B, код Джанго

# mysite.utilities.decorators.py
import settings

def HTTPS_Response(request, URL):
    if settings.SERVER_TYPE == "DEV":
        new_URL = URL
    else:
        absolute_URL = request.build_absolute_uri(URL)
        new_URL = "https%s" % absolute_URL[4:]
    return HttpResponseRedirect(new_URL)

# views.py

def show_items(request):
    if request.method == 'POST':
        newURL = handle_post(request)
        return HTTPS_Response(request, newURL) # replaces HttpResponseRedirect()
    else: # request.method == 'GET'
        theForm = handle_get(request)
    csrfContext = RequestContext(request, {'theForm': theForm,})
    return render_to_response('item-search.html', csrfContext)

def handle_post(request):
    URL = reverse('item-found') # name of view in urls.py
    item = request.REQUEST.get('item')
    full_URL = '%s?item=%s' % (URL, item)
    return full_URL

Обратите внимание, что можно переписать HTTPS_Response() в качестве декоратора .Преимущество было бы - не нужно проходить весь ваш код и заменять HttpResponseRedirect().Недостаток - вам нужно поставить декоратор перед HttpResponseRedirect(), который находится в Django на django.http.__init__.py.Я не хотел изменять код Django, но это зависит от вас - это, безусловно, один из вариантов.

5 голосов
/ 16 ноября 2011

если вы разместите весь свой сайт за https, вам не нужно беспокоиться об этом на стороне django. (при условии, что вам не нужно защищать ваши данные между nginx и django, только между пользователями и вашим сервером)

...