Jak wdrożyć witrynę tylko HTTPS za pomocą Django / nginx?

Moje pierwotne pytanie brzmiało jakwłączyć HTTPS dla strony logowania Django i jedyną odpowiedzią było to, że ja - uczynię całą stronę jako HTTPS-only .

Biorąc pod uwagę, że używam Django 1.3 i nginx, jaki jest prawidłowy sposób, aby strona była tylko HTTPS?

Jedna odpowiedź wspominała rozwiązanie middleware, ale miała zastrzeżenie:

Django nie może wykonać przekierowania SSL, zachowując dane POST. Proszę ustrukturyzować swoje poglądy tak, aby przekierowania występują tylko podczas get.

Pytanie o błąd serwera o nginx przepisując do https , wspomniano również o problemach z postami utraty danych, a ja nie jestem wystarczająco zaznajomiony z nginx, aby określić, jak dobrze działa rozwiązanie.

I zalecenie EFF, aby przejść tylko HTTPS , zauważa, że:

Aplikacja musi ustawić bezpieczny atrybut na pliku cookie, gdy ustawiam. Ten atrybut nakazuje przeglądarce wysyłanie pliku cookie tylko nad bezpieczny transport (HTTPS), nigdy niezabezpieczony (HTTP).

Czy aplikacje takie jak Django-auth mają możliwość ustawienia plików cookie jako Bezpieczne? Czy muszę pisać więcej middleware?

Więc, jaki jest najlepszy sposób na skonfigurowanie kombinacji Django / nginx, aby zaimplementować HTTPS-only, w kategoriach:

  • bezpieczeństwo
  • przechowywanie danych POST
  • cookies obsługiwane prawidłowo
  • interakcja z innymi aplikacjami Django (takimi jak Django-auth), działa poprawnie
  • any inne kwestie, których nie znam:)

Edit - kolejny problem, który właśnie odkryłem podczas testowania wielu przeglądarek. Powiedzmy, że mam URL https://mysite.com/search/, który ma formularz wyszukiwania / przycisk. Klikam przycisk, przetwarzam formularz w Django jak zwykle i wykonuję Django HttpResponseRedirect do http://mysite.com/search?results="foo". Nginx przekierowuje to do https://mysite.com/search?results="foo", zgodnie z życzeniem.

Jednak - Opera ma widoczny flash , gdy nastąpi przekierowanie. I zdarza się to przy każdym wyszukiwaniu, nawet dla tego samego szukanego terminu (Myślę, że https naprawdę nie buforuje:) gorzej, gdy testuję go w IE, najpierw dostaję wiadomość:

Zostaniesz przekierowany do połączenia, które nie jest bezpieczne - kontynuować?

Po kliknięciu "tak" natychmiast następuje:

Masz zamiar przeglądać strony przez bezpieczne połączenie-kontynuować?

Chociaż drugie Ostrzeżenie IE ma opcję wyłączenia - pierwsze ostrzeżenie nie ma, więc za każdym razem, gdy ktoś robi Szukaj i zostaje przekierowany do strony wyników, otrzymują co najmniej jeden komunikat ostrzegawczy.

Author: Community, 2011-11-16

3 answers

Dla drugiej części odpowiedzi Johna C i Django 1.4+...

Zamiast rozszerzać HttpResponseRedirect, możesz zmienić request.scheme na https. Ponieważ Django stoi za odwrotnym proxy Nginx, nie wie, że oryginalne żądanie było bezpieczne.

W Ustawieniach Django Ustaw SECURE_PROXY_SSL_HEADER ustawienie:

SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

Następnie musisz nginx ustawić niestandardowy nagłówek w odwrotnym proxy. W Ustawieniach strony Nginx:

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

Tędy request.scheme == 'https' i request.is_secure() zwraca True. request.build_absolute_uri() zwraca https://... i tak dalej...

 48
Author: yprez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-10 08:51:57

Oto rozwiązanie, które do tej pory opracowałem. Istnieją dwie części, Konfiguracja nginx i pisanie kodu dla Django. Część nginx obsługuje zewnętrzne żądania, przekierowuje http strony do https, A Kod Django obsługuje wewnętrzne generowanie URL, które ma prefiks http. (Przynajmniej te wynikające z HttpResponseRedirect()). W połączeniu wygląda na to, że działa dobrze - z tego co wiem, przeglądarka klienta nigdy nie widzi strony http, której użytkownicy sami nie wpisali.

[[17]}część pierwsza, konfiguracja 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;
    }
}

Część druga A, różne bezpieczne ustawienia plików cookie, od settings.py

SERVER_TYPE = "DEV"
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True # obecnie tylko w Dev gałęzi Django.
SESSION_EXPIRE_AT_BROWSER_CLOSE = True

Część druga B, Kod Django

# 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

Zauważ, że jest możliwe Napisz ponownie HTTPS_Response() jako dekorator . Zaletą byłoby to, że nie trzeba przechodzić przez cały kod i zastępować HttpResponseRedirect(). Wadą - musiałbyś umieścić dekoratora przed HttpResponseRedirect(), który jest w Django w django.http.__init__.py. Nie chciałem modyfikować kodu Django, ale to zależy od ciebie - to z pewnością jedna z opcji.

 21
Author: John C,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-07 20:53:43

Jeśli przykleisz całą swoją witrynę za https, nie musisz się o to martwić na końcu django. (zakładając, że nie musisz chronić swoich danych między nginx i django, tylko między użytkownikami a twoim serwerem)

 5
Author: second,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-16 16:14:14