¿Cómo puedo probar las conexiones https con Django tan fácilmente como las conexiones que no son https usando 'runserver'?

109

Tengo una aplicación que utiliza cookies "seguras" y quiero probar su funcionalidad sin necesidad de configurar un complicado servidor de desarrollo habilitado para SSL. ¿Hay alguna forma de hacer esto tan simplemente como puedo probar solicitudes no cifradas usando ./manage.py runserver?

Evan Grim
fuente
¿No puede simplemente especificar runserver 443 para que el servidor se ejecute en el puerto 443?
Furbeenator
@Furbeenator: Desafortunadamente no, esto solo hará que el servidor sea HTTP en 443, lo que necesito es un servidor SSL real en ejecución.
Evan Grim

Respuestas:

109

No es tan simple como el servidor de desarrollo integrado, pero no es demasiado difícil conseguir algo parecido utilizando stunnel como intermediario SSLificador entre su navegador y el servidor de desarrollo. Stunnel le permite configurar un servidor ligero en su máquina que acepta conexiones en un puerto configurado, las envuelve con SSL y las pasa a otro servidor. Usaremos esto para abrir un puerto de stunnel (8443) y pasar cualquier tráfico que reciba a una instancia de Django runserver.

Primero necesitará stunnel que se puede descargar aquí o puede ser proporcionado por el sistema de paquetes de su plataforma (por ejemplo :) apt-get install stunnel. Usaré la versión 4 de stunnel (por ejemplo: /usr/bin/stunnel4en Ubuntu), la versión 3 también funcionará, pero tiene diferentes opciones de configuración.

Primero cree un directorio en su proyecto Django para contener los archivos de configuración necesarios y el material SSLish.

mkdir stunnel
cd stunnel

A continuación, necesitaremos crear un certificado y una clave locales que se utilizarán para la comunicación SSL. Para ello recurrimos a openssl.

Crea la clave:

openssl genrsa 1024 > stunnel.key

Cree el certificado que usa esta clave (esto le pedirá un montón de información que se incluirá en el certificado; solo responda con lo que le parezca bien):

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

Ahora combine estos en un solo archivo que stunnel usará para su comunicación SSL:

cat stunnel.key stunnel.cert > stunnel.pem

Cree un archivo de configuración para stunnel llamado dev_https con el siguiente contenido:

pid=

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

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

Este archivo le dice a Stunnel lo que necesita saber. Específicamente, le está diciendo que no use un archivo pid, dónde está el archivo de certificado, qué versión de SSL usar, que debe ejecutarse en primer plano, dónde debe registrar su salida y que debe aceptar la conexión en el puerto. 8443 y trasládelos al puerto 8001. El último parámetro (TIMEOUTclose) le dice que cierre automáticamente la conexión después de que haya pasado 1 segundo sin actividad.

Ahora regrese al directorio de su proyecto Django (el que tiene manage.py en él):

cd ..

Aquí crearemos un script llamado runserver que ejecutará stunnel y dos servidores de desarrollo de django (uno para conexiones normales y otro para conexiones SSL):

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

Analicemos esto, línea por línea:

  • Línea 1: inicia stunnel y apúntalo al archivo de configuración que acabamos de crear. Esto hace que Stunnel escuche en el puerto 8443, envuelva las conexiones que reciba en SSL y las pase al puerto 8001
  • Línea 2: inicia una instancia normal de Django runserver (en el puerto 8000)
  • Línea 3: inicia otra instancia del servidor de ejecución de Django (en el puerto 8001) y la configura para tratar todas las conexiones entrantes como si se estuvieran realizando mediante HTTPS.

Haga que el archivo de ejecución que acabamos de crear sea ejecutable con:

chmod a+x runserver

Ahora, cuando desee ejecutar su servidor de desarrollo, simplemente ejecútelo ./runserverdesde el directorio de su proyecto. Para probarlo, simplemente apunte su navegador a http: // localhost: 8000 para el tráfico HTTP normal y https: // localhost: 8443 para el tráfico HTTPS. Tenga en cuenta que su navegador casi definitivamente se quejará del certificado utilizado y le pedirá que agregue una excepción o que indique explícitamente al navegador que continúe navegando. Esto se debe a que creó su propio certificado y el navegador no confía en él para decir la verdad sobre quién es. Esto está bien para el desarrollo, pero obviamente no será suficiente para la producción.

Desafortunadamente, en mi máquina, esta secuencia de comandos del servidor de ejecución no sale bien cuando presiono Ctrl-C. Tengo que matar manualmente los procesos, ¿alguien tiene una sugerencia para solucionarlo?

Gracias a la publicación de Michael Gile y la entrada wiki de django-weave por el material de referencia.

Evan Grim
fuente
3
Me acabo de encontrar con esta respuesta. Algunas observaciones: no es necesario ejecutar una instancia de desarrollo separada en 8001, también puede dejar que se conecte al puerto 8000. Si desea que el stunnel sea eliminado automáticamente, agregue una función y una trampa de salida: kill_stunnel () { kill $ stunnel_pid} trampa kill_stunnel salida stunnel4 stunnel / dev https & stunnel_pid = $ 1
Friek
2
La segunda instancia se invoca con HTTPS = 1, lo que significa que request.is_secure()informará True. Si no lo necesita, entonces tiene razón: puede apuntar stunnel a una sola instancia.
Evan Grim
Si se encuentra con el modo stunnel fips no es compatible ... agregue fips = no al archivo dev_https para apagarlo
yeahdixon
2
Acabo de probar esto porque estoy tratando de configurar una copia de desarrollo de un trabajo de sitio en un proyecto desarrollado por otra persona, pero lo estoy obteniendo "sslVersion = SSLv3": SSLv3 not supported.
HenryM
@Friek stunnel_pid=$1no funcionó para mí, pero lo stunnel_pid=$!hizo. ¿Cómo te stunnel_pid=$1funcionó?
Utku
86

Recomendaría usar el paquete django-sslserver .

El paquete actual en PyPI solo admite hasta la versión 1.5.5 de Django, pero se ha enviado un parche a través de 5d4664c . Con esta solución, el sistema funciona bien y es una solución bastante simple y directa para probar conexiones https.

ACTUALIZACIÓN: Desde que publiqué mi respuesta, la confirmación anterior se ha fusionado en la rama maestra y se ha enviado una nueva versión a PyPI. Por lo tanto, no debería ser necesario especificar la confirmación 5d4664c para esa solución específica.

devonbleibtrey
fuente
5
Esto parece prometedor; es posible que tenga que actualizar la respuesta aceptada en esta. ¿Alguien más quiere opinar?
Evan Grim
3
esta debería convertirse en la respuesta aceptada, utilizada durante un tiempo en un proyecto bastante complejo que simplemente no puede funcionar sin ejecutarse en https y nunca tuvo problemas.
Simone Cittadini
2
Funciona bien ... ¡Gracias! :)
nidHi
5
Funciona a partir de Python 3.6.2 y Django 1.11.3.
phoenix
2
Funciona a partir de Python 3.5 y Django 1.11
Hansel
64

Similar a django-sslserver, puede usar RunServerPlus desde django-extensions

Tiene dependencias en Werkzeug (por lo que tiene acceso al excelente depurador Werkzeug) y pyOpenSSL (solo se requiere para el modo ssl), así que para instalar ejecutar:

pip install django-extensions Werkzeug pyOpenSSL

Agréguelo a INSTALLED_APPS en el archivo settings.py de su proyecto:

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

Luego puede ejecutar el servidor en modo ssl con:

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

Esto creará un archivo de certificado en /tmp/cert.crty un archivo de clave en el /tmp/cert.keyque se puede reutilizar para futuras sesiones.

Hay un montón de cosas adicionales incluidas en django-extensions que puede resultarle útil, por lo que vale la pena echar un vistazo rápido a los documentos.

djsutho
fuente
2
En realidad, la mejor respuesta para Django 1.6+ ya que django-sslserver no admite la recarga automática para la nueva versión
Zat42
La mejor respuesta para depurar + activar SSL.
Yuda Prawira
Me pregunto por qué no funciona en la aplicación en contenedor Docker
Roel
@Roel lo intentó rápidamente y parece funcionar para una aplicación de hola mundo. podría ser que su imagen base no tenga las dependencias requeridas (por ejemplo, si usa -alpine) o es posible que deba abrir su rango de IP, por ejemplo./manage.py runserver_plus --cert /tmp/cert 0.0.0.0:8000
djsutho
FileNotFoundError: [Errno 2] No existe tal archivo o directorio: '/tmp\\cert.crt'
Mark Anthony Libres
38

solo instala

sudo pip install django-sslserver

incluir sslserver en aps instalados

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

ahora puedes correr

 python manage.py runsslserver 0.0.0.0:8888
Ryabchenko Alexander
fuente
2
¡La solución más limpia!
SexyBeast
de hecho, una solución limpia, pero por alguna razón, es muy lenta
Bhanu Tez
Mmm, Chrome está dando una advertencia de que el certificado no es válido.
zerohedge
@zerohedge es solo para desarrollo, por lo que no importa.
Sharpless512
esto es muy elegante, pero ¿hay alguna solución para usar esto para probar conexiones seguras? por ejemplo, si desea probar contra Facebook Graph API? developers.facebook.com/docs/graph-api/webhooks#setup
frednikgohar
14

Regístrese en https://ngrok.com/ . Puede usar https para probar. Esto podría ayudar a las personas que solo quieren probar https rápidamente.

Neil
fuente
6
Para una prueba rápida, esta es una gran solución. Y no tuve que registrarme para nada, solo descargar y ejecutar ./ngrok http 8000, 8000 es mi puerto de host local.
GavKilbride
4

Para aquellos que buscan una versión en primer plano de la opción stunnel con fines de depuración:

stunnel.pem es un certificado generado como en la respuesta más votada de Evan Grimm.

Escuche en todas las interfaces locales en el puerto 443 y reenvíe al puerto 80 en localhost

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

sudo solo es necesario para los puertos entrantes (-d [host:] puerto) por debajo de 1024

Micheal Lunny
fuente
4
  1. Instale ngrok. enlace de descarga: https://ngrok.com/download
  2. Emita el siguiente comando en la terminal

    ngrok http 8000

Comenzará la sesión ngrok. Enumerará dos URL. Uno está asignado a http: // localhost: 8000 . El segundo se asigna a https: // localhost: 8000 . Compruebe la captura de pantalla a continuación. Utilice cualquier URL. Se asignará a su servidor local.

captura de pantalla de la sesión ngrok de muestra

ABN
fuente
La forma más fácil de hacerlo, pero recuerde poner la nueva URL https en elallowed_host
Roel
2

Se puede hacer en una línea con socat:

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

, donde 8443 es un puerto para escuchar conexiones HTTPS entrantes, server.pem es un certificado de servidor autofirmado y localhost: 8000 es un servidor HTTP de depuración iniciado como de costumbre.

Más detalles: http://www.dest-unreach.org/socat/doc/socat-openssltunnel.html

uri.z
fuente
0

Maneje SSL / TLS con un proxy como Nginx en lugar de Django. Nginx se puede configurar para escuchar en el puerto 443 y luego reenviar solicitudes a su servidor de desarrollo Django (normalmente http://127.0.0.1:8000). Una configuración de Nginx para esto podría tener el siguiente aspecto:

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

También deberá asignar django-dev.localhosta 127.0.0.1y añadir django-dev.localhosta ALLOWED_HOSTSen settings.py. En Linux, deberá agregar la siguiente línea a /etc/hosts:

127.0.0.1   django-dev.localhost

Luego podrá llegar a su sitio de desarrollo yendo a https://django-dev.localhosten su navegador (deberá omitir la advertencia de seguridad de su navegador).

cincuenta y dos tarjetas
fuente