example django https nginx django-authentication

example - ¿Cómo implementar un sitio solo para HTTPS con Django/nginx?



gunicorn django (3)

Mi pregunta original fue cómo habilitar HTTPS para una página de inicio de sesión de Django y, como única respuesta, recomendé que: haga todo el sitio como solo HTTPS .

Dado que estoy usando Django 1.3 y nginx, ¿cuál es la forma correcta de hacer un sitio solo con HTTPS?

La única respuesta mencionaba una solución de middleware , pero tenía la advertencia:

Django no puede realizar una redirección SSL mientras mantiene los datos POST. Por favor, estructure sus vistas para que los redireccionamientos solo se produzcan durante los GET.

Una pregunta sobre la falla del servidor acerca de la reescritura de nginx a https , también mencionó problemas con POSTs perdiendo datos, y no estoy lo suficientemente familiarizado con nginx para determinar qué tan bien funciona la solución.

Y la recomendación de EFF de ir solo a HTTPS , observa que:

La aplicación debe establecer el atributo de seguridad en la cookie al configurarlo. Este atributo indica al navegador que envíe la cookie solo a través de transporte seguro (HTTPS), nunca inseguro (HTTP).

¿Las aplicaciones como Django-auth tienen la capacidad de establecer cookies como seguras? ¿O tengo que escribir más middleware?

Entonces, ¿cuál es la mejor manera de configurar la combinación de Django / nginx para implementar solo HTTPS, en términos de:

  • seguridad
  • preservación de datos POST
  • cookies manejadas adecuadamente
  • la interacción con otras aplicaciones de Django (como Django-auth) funciona correctamente
  • cualquier otro problema que no sepa :)

Editar : otro problema que acabo de descubrir, mientras probaba varios navegadores. Supongamos que tengo la URL https://mysite.com/search/ , que tiene un formulario / botón de búsqueda. Hago clic en el botón, proceso el formulario en Django como de costumbre y hago un Django HttpResponseRedirect a http://mysite.com/search?results="foo" . Nginx lo redirige a https://mysite.com/search?results="foo" , según lo desee.

Sin embargo, Opera tiene un flash visible cuando ocurre la redirección. Y sucede en todas las búsquedas, incluso para el mismo término de búsqueda (creo que https realmente no guarda en caché :) Peor aún, cuando lo pruebo en IE, primero obtengo el mensaje:

Estás a punto de ser redirigido a una conexión que no es segura, ¿continuar?

Después de hacer clic en "sí", esto es seguido inmediatamente por:

Está a punto de ver páginas a través de una conexión segura, ¿continuar?

Aunque la segunda advertencia de IE tiene una opción para desactivarla, la primera advertencia no, por lo que cada vez que alguien realiza una búsqueda y es redirigido a una página de resultados, recibe al menos un mensaje de advertencia.


Aquí está la solución que he resuelto hasta ahora. Hay dos partes, configurar nginx y escribir código para Django. La parte nginx maneja las solicitudes externas , redirecciona las páginas http a https , y el código Django maneja la generación interna de URL que tiene un prefijo http . (Al menos, los resultantes de un HttpResponseRedirect() ). Combinado, parece funcionar bien, hasta donde puedo decir, el navegador del cliente nunca ve una página http que los usuarios no escribieron ellos mismos.

Primera parte, configuración 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; } }

Parte dos A, varias configuraciones de cookies seguras, de settings.py

SERVER_TYPE = "DEV"
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True # actualmente solo en la rama Dev de Django.
SESSION_EXPIRE_AT_BROWSER_CLOSE = True

Parte dos B, código 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

Tenga en cuenta que es posible volver a escribir HTTPS_Response() como decorador . La ventaja sería no tener que pasar por todo su código y reemplazar HttpResponseRedirect() . La desventaja: tendrías que colocar el decorador frente a HttpResponseRedirect() , que está en Django en django.http.__init__.py . No quería modificar el código de Django, pero eso depende de usted, sin duda es una opción.


Para la segunda parte de la respuesta de John C, y Django 1.4 + ...

En lugar de extender HttpResponseRedirect, puede cambiar request.scheme a https . Como Django está detrás del proxy inverso de Nginx, no sabe que la solicitud original era segura.

En la configuración de Django, establezca la configuración SECURE_PROXY_SSL_HEADER :

SECURE_PROXY_SSL_HEADER = (''HTTP_X_FORWARDED_PROTO'', ''https'')

Entonces, necesita Nginx para configurar el encabezado personalizado en el proxy inverso. En la configuración del sitio Nginx:

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

De esta forma request.scheme == ''https'' y request.is_secure() devuelve True. request.build_absolute_uri() devuelve https://... y así sucesivamente ...


si coloca todo su sitio detrás de https, no necesita preocuparse por ello en el extremo de django. (suponiendo que no necesita proteger sus datos entre nginx y django, solo entre los usuarios y su servidor)