it-swarm.dev

Stai cercando di fare in modo che un sito basato su Django utilizzi solo HTTPS, non sei sicuro che sia sicuro?

Il EFF raccomanda sando HTTPS ovunque sul tuo sito, e sono sicuro che questo sito sarebbe d'accordo. Quando ho posto una domanda sull'utilizzo di Django per implementare HTTPS sulla mia pagina di accesso, è stato sicuramente la risposta che ho ricevuto :)

Quindi sto provando a fare proprio questo. Ho una configurazione di Django/nginx che sto cercando di configurare solo per HTTPS - è un po 'funzionante, ma ci sono problemi. Ancora più importante, sono sicuro che sia davvero sicuro , nonostante abbia visto https prefisso.

Ho configurato nginx per reindirizzare tutte le pagine http su https e quella parte funziona. Tuttavia ... Di 'che ho una pagina, https://mysite.com/search/, con un modulo/pulsante di ricerca su di esso. Faccio clic sul pulsante, Django elabora il modulo e fa un reindirizzamento a una pagina di risultati , che è http://mysite.com/search/results?term="foo".

Questo URL viene inviato al browser, che lo rimanda indietro al server nginx, che esegue un reindirizzamento permanente a un prefisso https- versione della pagina. (Almeno io penso questo è ciò che sta accadendo - sicuramente IE mi avverte che sto andando a una pagina non sicura e poi di nuovo a una pagina sicura :)

Ma questo è davvero sicuro? O almeno la stessa sicurezza di un sito standard solo HTTPS avrebbe? È il fatto che Django trasmette un URL con prefisso http, qualcuno che compromette la sicurezza? Sì, per quanto posso dire, solo le pagine che hanno un prefisso https ricevono risposta, ma non lo fa 't sento giusto :) La sicurezza è funky, come può testimoniare questo sito, e sono preoccupato che ci sia qualcosa che mi manca.

63
John C

Proteggi i tuoi cookie

In settings.py metti le linee

SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

e i cookie verranno inviati solo tramite connessioni HTTPS. Inoltre, probabilmente vuoi anche SESSION_EXPIRE_AT_BROWSER_CLOSE=True. Nota se stai utilizzando versioni precedenti di Django (meno di 1.4), non esiste un'impostazione per i cookie CSRF sicuri. Come soluzione rapida, puoi solo avere un cookie CSRF sicuro quando il il cookie di sessione è sicuro (SESSION_COOKIE_SECURE=True), modificando Django/middleware/csrf.py:

class CsrfViewMiddleware(object):
   ...
   def process_response(self, request, response):
       ...
       response.set_cookie(settings.CSRF_COOKIE_NAME,
            request.META["CSRF_COOKIE"], max_age = 60 * 60 * 24 * 7 * 52,
            domain=settings.CSRF_COOKIE_DOMAIN,
            secure=settings.SESSION_COOKIE_SECURE or None)

Richieste HTTP dirette a HTTPS nel server web

Quindi si desidera una regola di riscrittura che reindirizza le richieste http a https, ad esempio in nginx

server {
   listen 80;
   rewrite ^(.*) https://$Host$1 permanent;
}

La funzione reverse di Django e i tag modello url restituiscono solo collegamenti relativi; quindi se sei su una pagina https i tuoi link ti terranno sul sito https.

Impostare la variabile ambientale del sistema operativo HTTPS su on

Infine, (e la mia risposta originale lo ha escluso), devi abilitare la variabile ambientale del sistema operativo da HTTPS a 'on' so Django anteporrà https ai collegamenti completamente generati (ad esempio, come con HttpRedirectRequests). Se stai usando mod_wsgi, puoi aggiungere la riga:

os.environ['HTTPS'] = "on"

al tuo wsgi script . Se stai usando uwsgi, puoi aggiungere una variabile ambientale tramite l'opzione della riga di comando --env HTTPS=on o aggiungendo la riga env = HTTPS=on al tuo uwsgi .ini file. Come ultima risorsa, se non funziona nient'altro, puoi modificare il file delle impostazioni per avere le righe import os e os.environ['HTTPS'] = "on", che dovrebbe funzionare anche.

Se si utilizza wsgi, è possibile che si desideri impostare ulteriormente la variabile ambientale wsgi.url_scheme per 'https' aggiungendo questo al tuo settings.py:

os.environ['wsgi.url_scheme'] = 'https'

Il consiglio wsgi per gentile concessione di commento di Vijayendra Bapte .

Puoi vedere la necessità di questa variabile ambientale leggendo Django/http/__init__.py:

def build_absolute_uri(self, location=None):
    """
    Builds an absolute URI from the location and the variables available in
    this request. If no location is specified, the absolute URI is built on
    ``request.get_full_path()``.
    """
    if not location:
        location = self.get_full_path()
    if not absolute_http_url_re.match(location):
        current_uri = '%s://%s%s' % (self.is_secure() and 'https' or 'http',
                                     self.get_Host(), self.path)
        location = urljoin(current_uri, location)
    return iri_to_uri(location)

def is_secure(self):
    return os.environ.get("HTTPS") == "on"

Ulteriori cose sul server Web:

Prendi il consiglio di quel ragazzo e attiva le intestazioni HSTS nel tuo server web aggiungendo una linea a nginx:

add_header Strict-Transport-Security max-age=31536000;

Questo dice al tuo browser che il tuo sito web per i prossimi 10 anni utilizzerà solo HTTPS. Se si verifica un attacco man-in-the-middle in qualsiasi visita futura dallo stesso browser (ad esempio, si accede a un router dannoso in una caffetteria che ti reindirizza a una versione HTTP della pagina), il browser ricorderà si suppone che sia solo HTTPS e ti impedisce di rinunciare inavvertitamente alle tue informazioni. Ma fai attenzione, non puoi cambiare idea e in seguito decidi che parte del tuo dominio verrà servita su HTTP (fino a quando saranno trascorsi 10 anni da quando hai rimosso questa linea). Quindi pianificare in anticipo; ad esempio, se ritieni che la tua applicazione potrebbe presto aumentare di popolarità e dovrai essere su una grande CDN che non gestisce bene HTTPS a un prezzo che puoi permetterti, potresti avere un problema.

Assicurati anche di disabilitare i protocolli deboli. Invia il tuo dominio a Test SSL per verificare la presenza di potenziali problemi (chiave troppo breve, non usando TLSv1.2, usando protocolli non funzionanti, ecc.). Ad esempio, in nginx utilizzo:

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS";
67
dr jimbob

Il reindirizzamento da qualsiasi http: // alla pagina https: // corrispondente è l'approccio sbagliato. Configura nginx per reindirizzare la porta da 80 a https: //tuodominio.ext/

server {
       listen 80;
       rewrite ^/? https://$Host/ permanent;
 }

o simile (controlla il prossimo manuale di nginx vicino a te) e non eseguire affatto l'applicazione sulla porta 80 (http). Quindi, altre richieste sulla porta 80 si risolvono in un 404 o simile (personalizzalo, dicendo che la tua app è ora sicura e funziona solo su https con un link che punta a https: //tuodominio.ext/ ) . Quindi esegui la tua app solo sulla porta di ascolto 443 (https). L'uso di percorsi relativi nel tuo codice è ora sicuro, dal momento che tutti si risolvono nel percorso completo https: // ed eviti il ​​rimbalzo di http a https!

3
esskar

dovresti inoltre inviare un HSTS-Header da nginx, indicando ai client (browser) che dovranno usare solo HTTPS

add_header Strict-Transport-Security max-age=31536000;

Una configurazione comune ti inoltrerà il traffico https dal tuo server web (ad esempio Nginx) a un server http locale che esegue l'app Django.

In questo caso sarà più facile usare il SECURE_PROXY_SSL_HEADER setting (disponibile da Django 1.4.)

https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-SECURE_PROXY_SSL_HEADER

3
Sebastian

Penso che quello che stai cercando sia un Django middleware che riscriverà da http a https. Qualcosa di simile a ciò che viene indirizzato in questo domanda su SO , dove una risposta punta a questo middleware . Probabilmente dovrai scrivere il tuo middleware, ma dovrebbe essere semplice. (Una domanda ben focalizzata su SO ti farà puntare nella giusta direzione se hai bisogno di aiuto per iniziare.)

2
bstpierre

Nella maggior parte dei casi è possibile impostare Apache o qualcosa da reindirizzare a https, come descritto nella risposta accettata. E se puoi, sarebbe meglio, per le prestazioni e per i file serviti al di fuori di Django.

Ma se non puoi, o vuoi fare il debug, allora vorrei sottolineare che Django recentemente (1.8) ha introdotto un SecurityMiddleware che ha https-reindirizzamenti come uno dei suoi diverse funzioni.

Maggiori informazioni sono disponibili in la documentazione . Fondamentalmente, aggiungi Django.middleware.security.SecurityMiddleware e imposta SECURE_SSL_REDIRECT = True.

(L'intestazione menzionata dalla risposta accettata può anche essere impostata da questo middleware.)

2
Mark

Devi configurare Django per generare uno dei due

  1. https://domain/path si collega con il https: schema,
  2. //domain/path collegamenti senza schema (il browser li interpreterà come aventi lo stesso schema della pagina in cui è attualmente aperto), oppure
  3. /path collegamenti senza schema o dominio (il browser li interpreterà come aventi lo stesso schema e dominio della pagina attualmente indicata).
1
yfeldblum