2011-12-08 18 views
47

Ho un'applicazione python/django su Heroku (Stack di cedro) e vorrei renderlo accessibile solo tramite https. Ho abilitato l'opzione "ssl piggyback" e posso connettermi tramite https.Come rendere Python solo su https Heroku?

Ma qual è il modo migliore per disabilitare l'accesso http o il reindirizzamento a https?

risposta

63

Combinare la risposta di @CraigKerstiens e @allanlei in qualcosa che ho testato e verificato per funzionare. Heroku imposta il HTTP_X_FORWARDED_PROTO a https quando richiesta è SSL, e possiamo usare questo per controllare:

from django.conf import settings 
from django.http import HttpResponseRedirect 


class SSLMiddleware(object): 

    def process_request(self, request): 
     if not any([settings.DEBUG, request.is_secure(), request.META.get("HTTP_X_FORWARDED_PROTO", "") == 'https']): 
      url = request.build_absolute_uri(request.get_full_path()) 
      secure_url = url.replace("http://", "https://") 
      return HttpResponseRedirect(secure_url) 
+27

Answer è ora una [app su github] (https://github.com/rdegges/django-sslify) –

+1

Upvote per mettere su github ... Grazie! Proprio quello che stavo cercando oggi. –

+3

Come nota a margine, ciò non funziona se DEBUG è impostato su True. Passato un'ora a capire che è uscito, quindi spero che questo salvi qualcuno da qualche tempo. – Femi

6

Quale struttura si utilizza per l'applicazione? Se stai usando Django si potrebbe usare un po 'di semplice middleware simile a:

import re 

from django.conf import settings 
from django.core import urlresolvers 
from django.http import HttpResponse, HttpResponseRedirect 


class SSLMiddleware(object): 

    def process_request(self, request): 
     if not any([settings.DEBUG, request.is_secure()]): 
      url = request.build_absolute_uri(request.get_full_path()) 
      secure_url = url.replace("http://", "https://") 
      return HttpResponseRedirect(secure_url) 
+0

Sì, sto usando django. Grazie per la risposta: farò un tentativo a meno che non appaia qualcosa di più semplice (come un'opzione nascosta di heroku) .. – Kristian

+0

Ho dovuto fare un piccolo tweak per rispondere, ma i moderatori hanno rifiutato la mia modifica. Ho creato la mia risposta che risolve il problema con reindirizzamenti infiniti nella tua risposta attuale.Grazie comunque, non avrei mai pensato a una soluzione middleware senza il tuo contributo. – Kristian

+1

Questa soluzione crea un ciclo di reindirizzamento senza fine. Vedi la mia risposta sopra .. – Kristian

13

Non sono sicuro se @ CraigKerstiens di risposta tiene conto che request.is_secure() restituisce sempre False se dietro proxy inverso del Heroku e non "fisso". Se ricordo male, ciò causerebbe un loop di reindirizzamento HTTP.

Se si esegue Django con gunicorn, un altro modo per farlo è quello di aggiungere la seguente configurazione per di gunicorn

secure_scheme_headers = { 
    'X-FORWARDED-PROTO': 'https' 
} 

Run con alcuni, come questo nella vostra Procfile

web: python manage.py run_gunicorn -b 0.0.0.0:$PORT -c config/gunicorn.conf 

Impostando gunicorn di secure-scheme-header, request.is_secure() restituirà correttamente True su richieste https. Vedi Gunicorn Config.

Ora il middleware di CraigKerstiens funzionerà correttamente, comprese le chiamate a request.is_secure() nella tua app.

Nota: Django ha anche la stessa impostazione di configurazione chiamata SECURE_PROXY_SSL_HEADER, ma nella versione dev.

+2

L'impostazione django SECURE_PROXY_SSL_HEADER è ora disponibile in mainline (sicuramente in 1.6, forse prima). – Symmetric

4

Se stai usando Flask, questo funziona abbastanza bene:

1) Do "pip installare flask- sslify"

(GitHub è qui: https://github.com/kennethreitz/flask-sslify)

2) includere le seguenti righe:

from flask_sslify import SSLify 
if 'DYNO' in os.environ: # only trigger SSLify if the app is running on Heroku 
    sslify = SSLify(app) 
+0

Se lo facciamo ... abbiamo ancora bisogno di fare le cose di Heroku? scusa un po 'nuovo per questa roba – John

+0

Anche se vedi il problema "flip-flopping" su https://github.com/kennethreitz/flask-sslify/issues/3 – wodow

33

Django 1.8 avrà il supporto di base per non HTTPS reindirizzare (integrato da django-secure):

SECURE_SSL_REDIRECT = True # [1] 
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') 

Affinché SECURE_SSL_REDIRECT da trattare si deve usare il SecurityMiddleware:

MIDDLEWARE = [ 
    ... 
    'django.middleware.security.SecurityMiddleware', 
] 

[1] https://docs.djangoproject.com/en/1.8/ref/settings/#secure-ssl-redirect

+0

Questo significa che il pacchetto pip sslify è obsoleto a partire da Django 1.8? – dfrankow

+0

@dfrankow django-sslify suona in modo simile a django-secure, ma dovrai confermare che con l'autore del pacchetto – shangxiao

+0

@dfrankow No, hai ancora bisogno di sslify con Django 1.8, se vuoi reindirizzare automaticamente gli utenti da http a https . –