Come posso testare le connessioni https con Django con la stessa facilità con cui posso eseguire le connessioni non https usando "runserver"?


109

Ho un'applicazione che utilizza cookie "sicuri" e desidero testarne la funzionalità senza dover configurare un complicato server di sviluppo abilitato SSL. C'è un modo per farlo nel modo più semplice con cui posso testare le richieste non crittografate usando ./manage.py runserver?


Non puoi semplicemente specificare runserver 443 per far funzionare il server sulla porta 443?
Furbeenator

@Furbeenator: Purtroppo no - questo renderà il server HTTP su 443, quello di cui ho bisogno è un vero server SSL in esecuzione.
Evan Grim

Risposte:


109

Non è come semplice come il costruito nel server di sviluppo, ma non è troppo difficile ottenere qualcosa di simile utilizzando stunnel come intermediario SSLifying tra il browser e il server di sviluppo. Stunnel ti consente di configurare un server leggero sulla tua macchina che accetta connessioni su una porta configurata, le avvolge con SSL e le passa a un altro server. Lo useremo per aprire una porta stunnel (8443) e trasmettere tutto il traffico che riceve a un'istanza del server di esecuzione Django.

Per prima cosa avrai bisogno di stunnel che può essere scaricato qui o può essere fornito dal sistema di pacchetti della tua piattaforma (ad esempio:) apt-get install stunnel. Userò la versione 4 di stunnel (ad esempio: /usr/bin/stunnel4su Ubuntu), anche la versione 3 funzionerà, ma ha diverse opzioni di configurazione.

Per prima cosa crea una directory nel tuo progetto Django per contenere i file di configurazione necessari e le cose SSLish.

mkdir stunnel
cd stunnel

Successivamente dovremo creare un certificato locale e una chiave da utilizzare per la comunicazione SSL. Per questo ci rivolgiamo a openssl.

Crea la chiave:

openssl genrsa 1024 > stunnel.key

Crea il certificato che utilizza questa chiave (questo ti chiederà un mucchio di informazioni che saranno incluse nel certificato - rispondi semplicemente con ciò che ti fa sentire bene):

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

Ora combinali in un unico file che stunnel utilizzerà per la sua comunicazione SSL:

cat stunnel.key stunnel.cert > stunnel.pem

Crea un file di configurazione per stunnel chiamato dev_https con i seguenti contenuti:

pid=

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

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

Questo file dice a stunnel ciò che deve sapere. In particolare, gli stai dicendo di non usare un file pid, dove si trova il file del certificato, quale versione di SSL usare, che dovrebbe essere eseguito in primo piano, dove dovrebbe registrare il suo output e che dovrebbe accettare la connessione sulla porta 8443 e trasferirli alla porta 8001. L'ultimo parametro (TIMEOUTclose) indica di chiudere automaticamente la connessione dopo che è trascorso 1 secondo senza attività.

Ora torna alla directory del tuo progetto Django (quella con manage.py al suo interno):

cd ..

Qui creeremo uno script chiamato runserver che eseguirà stunnel e due server di sviluppo django (uno per le connessioni normali e uno per le connessioni SSL):

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

Analizziamo questo, riga per riga:

  • Riga 1: avvia stunnel e indirizzalo al file di configurazione che abbiamo appena creato. Questo ha l'ascolto stunnel sulla porta 8443, avvolge tutte le connessioni che riceve in SSL e le passa alla porta 8001
  • Riga 2: avvia una normale istanza del server di esecuzione Django (sulla porta 8000)
  • Riga 3: avvia un'altra istanza del server di esecuzione Django (sulla porta 8001) e la configura per trattare tutte le connessioni in entrata come se fossero eseguite utilizzando HTTPS.

Rendi eseguibile il file runscript che abbiamo appena creato con:

chmod a+x runserver

Ora, quando vuoi eseguire il tuo server di sviluppo, esegui semplicemente ./runserverdalla directory del progetto. Per provarlo, punta il tuo browser su http: // localhost: 8000 per il normale traffico HTTP e https: // localhost: 8443 per il traffico HTTPS. Tieni presente che il tuo browser si lamenterà quasi sicuramente del certificato utilizzato e ti richiederà di aggiungere un'eccezione o altrimenti istruirà esplicitamente il browser a continuare la navigazione. Questo perché hai creato il tuo certificato e non è considerato attendibile dal browser che dica la verità su chi sia. Questo va bene per lo sviluppo, ma ovviamente non lo taglierà per la produzione.

Sfortunatamente, sulla mia macchina questo script runserver non esce bene quando premo Ctrl-C. Devo terminare manualmente i processi: qualcuno ha un suggerimento per risolverlo?

Grazie al post di Michael Gile e alla voce wiki di django-weave per il materiale di riferimento.


4
Mi sono appena imbattuto in questa risposta. Alcune osservazioni: non è necessario eseguire un'istanza di sviluppo separata su 8001, potresti anche lasciarla connettere alla porta 8000. Se vuoi che lo stunnel venga ucciso automaticamente, aggiungi una funzione e un'uscita trap: kill_stunnel () { kill $ stunnel_pid} trap kill_stunnel exit stunnel4 stunnel / dev https & stunnel_pid = $ 1
Friek

2
La seconda istanza viene richiamata con HTTPS = 1, il che significa che request.is_secure()segnalerà True. Se non ne hai bisogno, hai ragione: puoi semplicemente puntare lo stunnel sulla singola istanza.
Evan Grim

Se ti imbatti in modalità fips stunnel non supportata ... aggiungi fips = no al file dev_https per disattivarlo
yeahdixon

2
L'ho appena provato mentre sto cercando di impostare una copia di sviluppo di un sito che funziona su un progetto sviluppato da qualcun altro, ma sto ottenendo "sslVersion = SSLv3": SSLv3 not supported.
HenryM

@Friek stunnel_pid=$1non ha funzionato per me, ma lo ha stunnel_pid=$!fatto. Come ha stunnel_pid=$1funzionato per te?
Utku

86

Suggerirei di utilizzare il pacchetto django-sslserver .

Il pacchetto corrente su PyPI supporta solo fino alla versione 1.5.5 di Django ma è stata eseguita una patch tramite 5d4664c . Con questa correzione il sistema funziona bene ed è una soluzione piuttosto semplice e diretta per testare le connessioni https.

AGGIORNAMENTO: da quando ho pubblicato la mia risposta, il commit sopra è stato unito al ramo principale e una nuova versione è stata inviata a PyPI. Quindi non dovrebbe essere necessario specificare il commit 5d4664c per quella specifica correzione.


5
Questo sembra promettente: potrei dover aggiornare la risposta accettata su questo. Qualcun altro vuole intervenire?
Evan Grim

3
questa dovrebbe diventare la risposta accettata, usata per un po 'in un progetto abbastanza complesso che semplicemente non può funzionare senza girare su https e non ha mai avuto problemi.
simone cittadini

2
Funziona bene ... Grazie! :)
nidHi

5
Funziona a partire da Python 3.6.2 e Django 1.11.3.
phoenix

2
Funziona a partire da Python 3.5 e Django 1.11
Hansel

64

Simile a django-sslserver potresti usare RunServerPlus da django-extensions

Ha dipendenze su Werkzeug (quindi puoi accedere all'eccellente debugger di Werkzeug) e pyOpenSSL (richiesto solo per la modalità ssl) quindi per installare esegui:

pip install django-extensions Werkzeug pyOpenSSL

Aggiungilo a INSTALLED_APPS nel file settings.py del tuo progetto:

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

Quindi puoi eseguire il server in modalità ssl con:

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

Questo creerà un file cert in /tmp/cert.crte un file chiave in /tmp/cert.keycui può essere riutilizzato per sessioni future.

C'è un sacco di cose extra incluse nelle estensioni di django che potresti trovare utili, quindi vale la pena dare una rapida occhiata ai documenti.


2
In realtà la migliore risposta per Django 1.6+ poiché django-sslserver non supporta il ricaricamento automatico per la nuova versione
Zat42

La migliore risposta per il debug e l'attivazione di SSL.
Yuda Prawira

Mi chiedo perché non funzioni nell'app containerizzata docker
Roel

@Roel ha provato velocemente e sembra funzionare per un'app Hello World. potrebbe essere che la tua immagine di base non abbia dipendenze richieste (ad es. se usi -alpine) o potresti dover aprire l'intervallo IP ad es./manage.py runserver_plus --cert /tmp/cert 0.0.0.0:8000
djsutho

FileNotFoundError: [Errno 2] Nessun file o directory di questo tipo: "/tmp\\cert.crt"
Mark Anthony Libres,

38

basta installare

sudo pip install django-sslserver

include sslserver negli aps installati

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

ora puoi correre

 python manage.py runsslserver 0.0.0.0:8888

2
La soluzione più pulita!
SexyBeast

davvero una soluzione pulita, ma per qualche motivo è molto lenta
Bhanu Tez

Hmm, Chrome sta dando un avviso che il certificato non è valido.
zerohedge

@zerohedge è solo per lo sviluppo, quindi non importa.
Sharpless512

questo è molto elegante, ma esiste una soluzione per usarlo per testare connessioni sicure? ad esempio, se vuoi testare l'API Graph di Facebook? sviluppatori.facebook.com/docs/graph-api/webhooks#setup
frednikgohar

14

Iscriviti a https://ngrok.com/ . Puoi usare https per testare. Questo potrebbe aiutare le persone che vogliono solo testare rapidamente https.


6
Per un rapido test questa è un'ottima soluzione. E non dovevo registrarmi per nulla, bastava scaricare ed eseguire ./ngrok http 8000, 8000 è la mia porta localhost.
GavKilbride

4

Per coloro che cercano una versione in primo piano dell'opzione stunnel per scopi di debug:

stunnel.pem è un certificato generato come nella risposta più votata di Evan Grimm.

Ascolta su tutte le interfacce locali sulla porta 443 e inoltra alla porta 80 su localhost

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

sudo è necessario solo per le porte in entrata (-d [host:] port) sotto 1024


4
  1. Installa ngrok. link per il download: https://ngrok.com/download
  2. Emettere il seguente comando sul terminale

    ngrok http 8000

Inizierà la sessione di ngrok. Elencherà due URL. Uno è mappato su http: // localhost: 8000 . Il secondo è mappato su https: // localhost: 8000 . Si prega di controllare lo screenshot qui sotto. Usa uno degli URL. Sarà mappato al tuo server locale.

screenshot della sessione di ngrok di esempio


Il modo più semplice per farlo, ma ricorda di inserire il nuovo URL https inallowed_host
Roel

2

Può essere fatto in una riga con socat:

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

, dove 8443 è una porta per ascoltare le connessioni HTTPS in entrata, server.pem è un certificato server autofirmato e localhost: 8000 è un server HTTP di debug lanciato come al solito.

Maggiori dettagli: http://www.dest-unreach.org/socat/doc/socat-openssltunnel.html


0

Gestisci SSL / TLS con un proxy come Nginx anziché Django. Nginx può essere configurato per ascoltare sulla porta 443 e quindi inoltrare le richieste al tuo server di sviluppo Django (in genere http://127.0.0.1:8000). Una configurazione Nginx per questo potrebbe essere la seguente:

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;
    }
}

Avrete anche bisogno di mappare django-dev.localhostper 127.0.0.1e aggiungere django-dev.localhosta ALLOWED_HOSTSin settings.py. Su Linux, dovrai aggiungere la seguente riga a /etc/hosts:

127.0.0.1   django-dev.localhost

Sarai quindi in grado di raggiungere il tuo sito di sviluppo accedendo al https://django-dev.localhosttuo browser (dovrai bypassare l'avviso di sicurezza del tuo browser).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.