Jak mogę przetestować połączenia HTTPS z Django tak łatwo, jak połączenia inne niż HTTPS przy użyciu 'runerver'?

109

Mam aplikację korzystającą z „bezpiecznych” plików cookie i chcę przetestować jej funkcjonalność bez konieczności konfigurowania skomplikowanego serwera programistycznego obsługującego protokół SSL. Czy istnieje sposób, aby to zrobić tak prosto, jak mogę przetestować niezaszyfrowane żądania za pomocą ./manage.py runserver?

Evan Grim
źródło
Czy nie możesz po prostu określić serwera uruchomieniowego 443, aby serwer działał na porcie 443?
Furbeenator
@Furbeenator: Niestety nie - spowoduje to po prostu HTTP na serwerze 443, potrzebuję aktualnego serwera SSL.
Evan Grim

Odpowiedzi:

109

To nie jest tak proste, jak wbudowany serwer deweloperski, ale nie jest zbyt trudno uzyskać coś bliskiego za pomocą stunnel jako pośrednika SSL między przeglądarką a serwerem programistycznym. Stunnel umożliwia skonfigurowanie na komputerze lekkiego serwera, który akceptuje połączenia na skonfigurowanym porcie, otacza je SSL i przekazuje je do innego serwera. Użyjemy tego do otwarcia portu stunnel (8443) i przekażemy cały ruch, który otrzyma do instancji serwera uruchomieniowego Django.

Najpierw będziesz potrzebować stunnela, który można pobrać tutaj lub może być dostarczony przez system pakietów Twojej platformy (np apt-get install stunnel.:). Będę używał wersji 4 stunnel (np. /usr/bin/stunnel4Na Ubuntu), wersja 3 też będzie działać, ale ma inne opcje konfiguracji.

Najpierw utwórz katalog w swoim projekcie Django, aby przechowywać niezbędne pliki konfiguracyjne i elementy SSL.

mkdir stunnel
cd stunnel

Następnie musimy utworzyć lokalny certyfikat i klucz, który będzie używany do komunikacji SSL. W tym celu zwracamy się do openssl.

Utwórz klucz:

openssl genrsa 1024 > stunnel.key

Utwórz certyfikat, który używa tego klucza (poprosi Cię to o kilka informacji, które zostaną zawarte w certyfikacie - po prostu odpowiedz, podając to, co Ci odpowiada):

openssl req -new -x509 -nodes -sha1 -days 365 -key stunnel.key > stunnel.cert

Teraz połącz je w jeden plik, którego stunnel będzie używał do komunikacji SSL:

cat stunnel.key stunnel.cert > stunnel.pem

Utwórz plik konfiguracyjny dla stunnel o nazwie dev_https z następującą zawartością:

pid=

cert = stunnel/stunnel.pem
sslVersion = SSLv3
foreground = yes
output = stunnel.log

[https]
accept=8443
connect=8001
TIMEOUTclose=1

Ten plik mówi stunnelowi, co powinien wiedzieć. Mówiąc konkretnie, mówisz mu, aby nie używał pliku pid, gdzie znajduje się plik certyfikatu, jakiej wersji SSL użyć, że powinien działać na pierwszym planie, gdzie powinien rejestrować swoje dane wyjściowe i że powinien akceptować połączenie na porcie 8443 i prześlij je do portu 8001. Ostatni parametr (TIMEOUTclose) nakazuje mu automatyczne zamknięcie połączenia po upływie 1 sekundy bez aktywności.

Teraz wyskakuj z powrotem do katalogu projektu Django (tego z manage.py):

cd ..

Tutaj utworzymy skrypt o nazwie runerver, który będzie uruchamiał stunnel i dwa serwery programistyczne django (jeden dla normalnych połączeń, a drugi dla połączeń SSL):

stunnel4 stunnel/dev_https &
python manage.py runserver&
HTTPS=1 python manage.py runserver 8001

Podzielmy to, linia po linii:

  • Linia 1: uruchamia stunnel i wskazuje plik konfiguracyjny, który właśnie utworzyliśmy. To nasłuchuje stunnel na porcie 8443, zawija wszystkie otrzymywane połączenia w SSL i przekazuje je dalej do portu 8001
  • Wiersz 2: Uruchamia zwykłą instancję uruchomieniową Django (na porcie 8000)
  • Linia 3: Uruchamia kolejną instancję serwera uruchomieniowego Django (na porcie 8001) i konfiguruje ją tak, aby traktować wszystkie połączenia przychodzące tak, jakby były wykonywane przy użyciu HTTPS.

Spraw, aby utworzony plik Runcript był wykonywalny za pomocą:

chmod a+x runserver

Teraz, gdy chcesz uruchomić serwer deweloperski, po prostu wykonaj ./runserverz katalogu projektu. Aby to wypróbować, po prostu skieruj swoją przeglądarkę na http: // localhost: 8000 dla normalnego ruchu HTTP i https: // localhost: 8443 dla ruchu HTTPS. Zauważ, że Twoja przeglądarka prawie na pewno będzie narzekać na używany certyfikat i wymagać dodania wyjątku lub w inny sposób wyraźnie poinstruuj przeglądarkę, aby kontynuowała przeglądanie. Dzieje się tak, ponieważ utworzyłeś swój własny certyfikat i przeglądarka nie ufa, że ​​mówi prawdę o tym, kto to jest. Jest to dobre do programowania, ale oczywiście nie nadaje się do produkcji.

Niestety, na mojej maszynie ten skrypt uruchomieniowy nie wychodzi dobrze po naciśnięciu Ctrl-C. Muszę ręcznie zabić procesy - ktoś ma sugestię, jak to naprawić?

Podziękowania dla posta Michaela Gile'a i wpisu wiki django-weave za materiał referencyjny.

Evan Grim
źródło
4
Właśnie natknąłem się na tę odpowiedź. Kilka uwag: niekoniecznie musisz uruchamiać osobną instancję programistyczną na 8001, równie dobrze możesz pozwolić jej połączyć się z portem 8000. Jeśli chcesz, aby stunnel był zabijany automatycznie, dodaj funkcję i pułapkę wyjściową: kill_stunnel () { kill $ stunnel_pid} pułapka kill_stunnel wyjście stunnel4 stunnel / dev https & stunnel_pid = 1 $
Friek
2
Druga instancja jest wywoływana z HTTPS = 1, co oznacza, że request.is_secure()będzie raportować True. Jeśli tego nie potrzebujesz, masz rację - możesz po prostu skierować stunnel na jedną instancję.
Evan Grim
Jeśli napotkasz tryb stunnel fips, który nie jest obsługiwany ... dodaj fips = no do pliku dev_https, aby go wyłączyć
yeahdixon
2
Właśnie spróbowałem tego, próbując skonfigurować kopię deweloperską strony internetowej nad projektem opracowanym przez kogoś innego, ale otrzymuję "sslVersion = SSLv3": SSLv3 not supported.
HenryM
@Friek stunnel_pid=$1nie pracował dla mnie, ale stunnel_pid=$!tak. Jak ci się udało stunnel_pid=$1?
Utku
86

Polecam użycie pakietu django-sslserver .

Obecny pakiet na PyPI obsługuje tylko do wersji Django 1.5.5, ale poprawka została zatwierdzona przez 5d4664c . Dzięki tej poprawce system działa dobrze i jest dość prostym i prostym rozwiązaniem do testowania połączeń https.

AKTUALIZACJA: Odkąd opublikowałem moją odpowiedź, powyższe zatwierdzenie zostało włączone do gałęzi master, a nowe wydanie zostało przesłane do PyPI. Więc nie powinno być potrzeby określania zatwierdzenia 5d4664c dla tej konkretnej poprawki.

devonbleibtrey
źródło
5
Wygląda to obiecująco - być może będę musiał zaktualizować zaakceptowaną odpowiedź w tej. Czy ktoś jeszcze chce się zważyć?
Evan Grim
3
powinno to stać się akceptowaną odpowiedzią, używaną przez jakiś czas w dość złożonym projekcie, który po prostu nie może działać bez uruchamiania na https i nigdy nie miał problemów.
simone cittadini
2
Działa dobrze ... Dzięki! :)
nidHi 12-16
5
Działa od Pythona 3.6.2 i Django 1.11.3.
feniks
2
Działa od Python 3.5 i Django 1.11
Hansel
64

Podobnie jak django-sslserver, możesz użyć RunServerPlus z django-extensions

Ma zależności od Werkzeug (więc masz dostęp do doskonałego debuggera Werkzeug) i pyOpenSSL (wymagane tylko w trybie ssl), więc aby zainstalować uruchom:

pip install django-extensions Werkzeug pyOpenSSL

Dodaj go do INSTALLED_APPS w pliku settings.py projektów:

INSTALLED_APPS = (
    ...
    'django_extensions',
    ...
)

Następnie możesz uruchomić serwer w trybie ssl za pomocą:

./manage.py runserver_plus --cert /tmp/cert

Spowoduje to utworzenie pliku certyfikatów pod adresem /tmp/cert.crti pliku klucza, w /tmp/cert.keyktórym można będzie ponownie użyć go w przyszłych sesjach.

Jest kilka dodatkowych rzeczy zawartych w rozszerzeniach django, które mogą okazać się przydatne, dlatego warto szybko przejrzeć dokumentację.

djsutho
źródło
2
Właściwie najlepsza odpowiedź dla Django 1.6+, ponieważ django-sslserver nie obsługuje automatycznego przeładowania dla nowej wersji
Zat42
Najlepsza odpowiedź na debugowanie + aktywacja SSL.
Yuda Prawira
Zastanawiam się, dlaczego nie działa w kontenerowej aplikacji
docker
@Roel spróbował szybko i wygląda na to, że działa w przypadku aplikacji Hello world. może być, że twój obraz podstawowy nie ma wymaganych zależności (np. jeśli używasz -alpine) lub może być konieczne otwarcie zakresu adresów IP, np../manage.py runserver_plus --cert /tmp/cert 0.0.0.0:8000
djsutho
FileNotFoundError: [Errno 2] Nie ma takiego pliku lub katalogu: „/tmp\\cert.crt”
Mark Anthony Libres
38

po prostu zainstaluj

sudo pip install django-sslserver

dołącz serwer ssl do zainstalowanych aps

INSTALLED_APPS = (...
"sslserver",
...
)

teraz możesz biec

 python manage.py runsslserver 0.0.0.0:8888
Ryabchenko Alexander
źródło
2
Najczystsze rozwiązanie!
SexyBeast
rzeczywiście czyste rozwiązanie, ale z jakiegoś powodu jest bardzo powolne
Bhanu Tez
Hmm, Chrome ostrzega, że ​​certyfikat jest nieważny.
zerohedge
@zerohedge jest tylko dla rozwoju, więc nie ma to znaczenia.
Sharpless512
to jest bardzo eleganckie - ale czy jest jakieś rozwiązanie do testowania bezpiecznych połączeń? na przykład, jeśli chcesz przetestować z Facebook Graph API? developers.facebook.com/docs/graph-api/webhooks#setup
frednikgohar
14

Zarejestruj się na https://ngrok.com/ . Możesz użyć https do testowania. Może to pomóc osobom, które chcą po prostu szybko przetestować https.

Neil
źródło
6
Na szybki test jest to świetne rozwiązanie. I nie musiałem się rejestrować, po prostu pobierz i uruchom ./ngrok http 8000, 8000 to mój port hosta lokalnego.
GavKilbride
4

Dla tych, którzy szukają pierwszoplanowej wersji opcji stunnel do celów debugowania:

stunnel.pem to certyfikat wygenerowany zgodnie z najczęściej głosowaną odpowiedzią Evana Grimma.

Nasłuchuj na wszystkich interfejsach lokalnych na porcie 443 i przekierowuj na port 80 na hoście lokalnym

sudo stunnel -f -p stunnel.pem -P ~/stunnel.pid -r localhost:80 -d 443

sudo jest konieczne tylko dla portów przychodzących (-d [host:] port) poniżej 1024

Micheal Lunny
źródło
4
  1. Zainstaluj ngrok. link do pobrania: https://ngrok.com/download
  2. Wydaj następujące polecenie na terminalu

    ngrok http 8000

Rozpocznie się sesja ngrok. Wyświetli dwa adresy URL. Jeden jest odwzorowany na http: // localhost: 8000 . Drugi jest mapowany na https: // localhost: 8000 . Sprawdź poniższy zrzut ekranu. Użyj dowolnego adresu URL. Zostanie zmapowany na twój lokalny serwer.

przykładowy zrzut ekranu sesji ngrok

ABN
źródło
Najłatwiej to zrobić, ale pamiętaj, aby umieścić nowy adres URL https wallowed_host
Roel,
2

Można to zrobić w jednej linii z socat:

socat openssl-listen:8443,fork,reuseaddr,cert=server.pem,verify=0 tcp:localhost:8000

, gdzie 8443 to port do nasłuchiwania przychodzących połączeń HTTPS, server.pem to samopodpisany certyfikat serwera, a localhost: 8000 to debugujący serwer HTTP uruchamiany jak zwykle.

Więcej szczegółów: http://www.dest-unreach.org/socat/doc/socat-openssltunnel.html

uri.z
źródło
0

Obsługuj SSL / TLS za pomocą serwera proxy, takiego jak Nginx, a nie Django. Nginx można skonfigurować tak, aby nasłuchiwał na porcie 443, a następnie przekazywał żądania do serwera deweloperskiego Django (zazwyczaj http://127.0.0.1:8000). Konfiguracja Nginx do tego może wyglądać następująco:

server {
    listen 443 ssl;
    server_name django-dev.localhost;

    ssl_certificate /etc/ssl/certs/nginx_chain.pem;
    ssl_certificate_key /etc/ssl/private/nginx.pem;    

    location / {
        proxy_pass http://127.0.0.1:8000/;
        proxy_set_header Host $host;
    }
}

Musisz również mapować django-dev.localhostdo 127.0.0.1i dodać django-dev.localhostdo ALLOWED_HOSTSw settings.py. W systemie Linux musisz dodać następujący wiersz do /etc/hosts:

127.0.0.1   django-dev.localhost

Będziesz wtedy mógł przejść do swojej witryny deweloperskiej, przechodząc do https://django-dev.localhostprzeglądarki (będziesz musiał ominąć ostrzeżenie o zabezpieczeniach przeglądarki).

pięćdziesiąt dwie karty
źródło