Как развернуть сайт только HTTPS, с Django / nginx?

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

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

один упомянутый ответ промежуточного решения, но с оговоркой:

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

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

и рекомендация EFF перейти только HTTPS указано следующее:

приложение должно установить атрибут Secure в файле cookie, когда установив его. Этот атрибут указывает браузеру отправить файл cookie только через безопасный (HTTPS) транспорт, никогда небезопасный (HTTP).

есть ли у приложений, таких как Django-auth, возможность устанавливать куки как безопасные? Или мне нужно написать больше промежуточного ПО?

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

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

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

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

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

после нажатия кнопки " да " сразу же следует:

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

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

3 ответов


для 2-й части ответа Джона C и Django 1.4+...

вместо расширения HttpResponseRedirect, вы можете изменить request.scheme to 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://... и так далее...


вот решение, которое я разработал до сих пор. Есть две части, настройка 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.
SESSION_EXPIRE_AT_BROWSER_CLOSE = True

Часть вторая 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, но это зависит от вас - это, безусловно, один из вариантов.


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