¿Intento que un sitio basado en Django use solo HTTPS, no estoy seguro si es seguro?

62

El EFF recomienda usar HTTPS en todas partes en su sitio, y estoy seguro de que este sitio estaría de acuerdo . Cuando hice una pregunta sobre el uso de Django para implementar HTTPS en mi página de inicio de sesión, ciertamente fue la respuesta que obtuve :)

Así que estoy tratando de hacer precisamente eso. Tengo una configuración de Django / nginx que estoy tratando de configurar solo para HTTPS. Está funcionando, pero hay problemas. Más importante aún, estoy seguro de que es realmente seguro , a pesar de ver el prefijo enlace .

He configurado nginx para redirigir todas las páginas http a https, y esa parte funciona. Sin embargo ... Digamos que tengo una página, https://mysite.com/search/ , con un formulario / botón de búsqueda en ella. Al hacer clic en el botón, Django procesa el formulario y redirige a una página de resultados , que es http://mysite.com/search/results?term="foo" .

Esta URL se envía al navegador, que la envía atrás al servidor nginx, que realiza un redireccionamiento permanente a una versión de la página con un prefijo https -prefixed. (Al menos, creo que eso es lo que está pasando. Ciertamente, IE me advierte que voy a una página insegura, y luego de vuelta a una página segura :)

¿Pero es realmente seguro? O, ¿al menos la misma seguridad que tendría un sitio estándar de HTTPS? ¿El hecho de que Django transmita una URL de prefijo http, alguien está comprometiendo la seguridad? Sí, por lo que puedo decir, solo se responde a las páginas que tienen un prefijo https, pero simplemente no se siente bien :) La seguridad es extravagante, como lo demuestra este sitio, y Me preocupa que haya algo que me esté perdiendo.

    
pregunta John C 16.11.2011 - 21:46
fuente

7 respuestas

66

Asegure sus cookies

En settings.py ponga las líneas

SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

y las cookies solo se enviarán a través de conexiones HTTPS. Además, probablemente también desee SESSION_EXPIRE_AT_BROWSER_CLOSE=True . Tenga en cuenta que si está utilizando versiones anteriores de django (menos de 1.4), no hay una configuración para cookies CSRF seguras. Como solución rápida, puede hacer que la cookie CSRF esté segura cuando la cookie de sesión sea segura ( SESSION_COOKIE_SECURE=True ), editando 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)

Solicitudes HTTP directas a HTTPS en el servidor web

A continuación, desea una regla de reescritura que redirija las solicitudes http a https, por ejemplo, en nginx

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

La función reverse de Django y las etiquetas de la plantilla url solo devuelven enlaces relativos; por lo tanto, si se encuentra en una página https, sus enlaces lo mantendrán en el sitio https.

Establezca la variable de entorno del sistema operativo HTTPS en onhh>

Finalmente, (y mi respuesta original lo excluyó), debe habilitar la variable ambiental del sistema operativo HTTPS a 'on' para que django anteponga https a los enlaces completamente generados (por ejemplo, como con HttpRedirectRequest s). Si está utilizando mod_wsgi, puede agregar la línea:

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

a su secuencia de comandos wsgi . Si está utilizando uwsgi, puede agregar una variable de entorno con el interruptor de línea de comando --env HTTPS=on o agregando la línea env = HTTPS=on a su archivo uwsgi .ini . Como último recurso, si nada más funciona, puede editar su archivo de configuración para que tenga las líneas import os y os.environ['HTTPS'] = "on" , que también deberían funcionar.

Si está utilizando wsgi, es posible que desee configurar adicionalmente la variable de entorno wsgi.url_scheme a 'https' agregando esto a su settings.py :

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

El consejo de wsgi es cortesía de Comentario de Vijayendra Bapte .

Puede ver la necesidad de esta variable de entorno leyendo 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"

Cosas adicionales del servidor web:

Tome el consejo de ese chico y active los encabezados HSTS en su servidor web agregando una línea a nginx:

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

Esto le indica a su navegador web que su sitio web durante los próximos 10 años usará solo HTTPS. Si hay algún ataque Man-in-the-middle en una visita futura desde el mismo navegador (por ejemplo, inicia sesión en un enrutador malicioso en una cafetería que lo redirige a una versión HTTP de la página), su navegador recordará se supone que debe ser solo HTTPS y le impide entregar inadvertidamente su información. Pero tenga cuidado con esto, no puede cambiar de opinión y luego decidir que parte de su dominio se servirá a través de HTTP (hasta que pasen los 10 años desde que eliminó esta línea). Así que planea con anticipación; por ejemplo, si cree que su aplicación pronto crecerá en popularidad y deberá estar en un CDN grande que no maneja bien el HTTPS a un precio que puede pagar, puede tener un problema.

También asegúrate de desactivar los protocolos débiles. Envíe su dominio a una SSL Test para verificar posibles problemas (clave demasiado corta, no usar TLSv1.2, usar protocolos rotos, etc.). Por ejemplo, en nginx uso:

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";
    
respondido por el dr jimbob 17.03.2017 - 14:14
fuente
3

La redirección de cualquier http: // a la página https: // correspondiente es un enfoque incorrecto. Configure nginx para redireccionar el puerto 80 a enlace

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

o similar (consulte el siguiente manual de nginx cerca de usted) y no ejecute su aplicación en absoluto en el puerto 80 (http). Entonces, otras solicitudes en el puerto 80 se resuelven en un 404 o similar (personalícelo, diciendo que su aplicación ahora es segura y se ejecuta solo en https con un enlace que apunta a enlace ). Luego ejecute su aplicación solo en el puerto de escucha 443 (https). El uso de rutas relativas en su código ahora es seguro, ya que todas se resuelven en la ruta https: // completa y usted evita que el http a https rebote.

    
respondido por el esskar 17.11.2011 - 00:19
fuente
3

Una configuración común le hará reenviar el tráfico https desde su servidor web (es decir, Nginx) a un servidor http local que ejecuta la aplicación Django.

En este caso, será más fácil usar la configuración SECURE_PROXY_SSL_HEADER (disponible desde Django 1.4.)

enlace

    
respondido por el Sebastian 09.07.2012 - 23:43
fuente
3

además debe enviar un HSTS-Header , indicando a los clientes (navegadores) que solo usarán HTTPS

add_header Strict-Transport-Security max-age=31536000;
    
respondido por el that guy from over there 14.07.2013 - 18:08
fuente
2

Creo que lo que estás buscando es un middleware de Django que reescriba http a https . Algo similar a lo que se aborda en esta pregunta en SO , donde una respuesta apunta a este middleware . Probablemente tendrás que escribir tu propio middleware, pero debería ser sencillo. (Una pregunta bien enfocada sobre SO le indicará en la dirección correcta si necesita ayuda para comenzar).

    
respondido por el bstpierre 17.11.2011 - 16:08
fuente
2

En la mayoría de los casos, puede configurar Apache o algo para redirigir a https, como se describe en la respuesta aceptada. Y si puede, sería mejor, para el rendimiento y para los archivos servidos fuera de Django.

Pero si no puede, o quiere hacer la depuración, entonces me gustaría señalar que Django introdujo recientemente (1.8) un SecurityMiddleware que tiene https-redirects como una de sus varias funciones.

Más información está disponible en la documentación . Básicamente, agregue django.middleware.security.SecurityMiddleware y establezca SECURE_SSL_REDIRECT = True .

(Este encabezado también puede establecer el encabezado mencionado por la respuesta aceptada).

    
respondido por el Mark 14.06.2015 - 14:22
fuente
1

Necesitas configurar django para generar cualquiera de estos

  1. https://domain/path enlaza con el esquema https: ,
  2. //domain/path enlaza sin esquema (el navegador interpretará que tienen el mismo esquema que la página en la que está abierto actualmente), o
  3. /path enlaza sin esquema o dominio (el navegador interpretará que tienen el mismo esquema y dominio que la página a la que apunta actualmente).
respondido por el yfeldblum 18.11.2011 - 03:07
fuente

Lea otras preguntas en las etiquetas