Como posso testar conexões https com Django tão facilmente quanto faço conexões não https usando 'runserver'?

109

Tenho um aplicativo que usa cookies "seguros" e desejo testar sua funcionalidade sem precisar configurar um servidor de desenvolvimento habilitado para SSL complicado. Existe alguma maneira de fazer isso da mesma forma que posso testar solicitações não criptografadas usando ./manage.py runserver?

Evan Grim
fonte
Você não pode simplesmente especificar runserver 443 para fazer o servidor rodar na porta 443?
Furbeenator
@Furbeenator: Infelizmente não - isso apenas tornará o servidor HTTP em 443, o que eu preciso é de um servidor SSL real em execução.
Evan Grim

Respostas:

109

Não é tão simples quanto o servidor de desenvolvimento integrado, mas não é muito difícil chegar perto usando o stunnel como um intermediário SSLificador entre o seu navegador e o servidor de desenvolvimento. O Stunnel permite que você configure um servidor leve em sua máquina que aceita conexões em uma porta configurada, envolve-as com SSL e as passa adiante para algum outro servidor. Usaremos isso para abrir uma porta de stunnel (8443) e passar qualquer tráfego que receber para uma instância de servidor de execução do Django.

Primeiro você precisará do stunnel, que pode ser baixado aqui ou pode ser fornecido pelo sistema de pacotes da sua plataforma (por exemplo apt-get install stunnel:). Vou usar a versão 4 do stunnel (por exemplo: /usr/bin/stunnel4no Ubuntu), a versão 3 também funcionará, mas tem opções de configuração diferentes.

Primeiro crie um diretório em seu projeto Django para manter os arquivos de configuração necessários e coisas SSLish.

mkdir stunnel
cd stunnel

Em seguida, precisaremos criar um certificado local e uma chave a ser usada para a comunicação SSL. Para isso, recorremos ao openssl.

Crie a chave:

openssl genrsa 1024 > stunnel.key

Crie o certificado que usa esta chave (isso irá pedir-lhe um monte de informações que serão incluídas no certificado - apenas responda com o que achar melhor):

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

Agora combine-os em um único arquivo que o stunnel usará para sua comunicação SSL:

cat stunnel.key stunnel.cert > stunnel.pem

Crie um arquivo de configuração para o stunnel chamado dev_https com o seguinte conteúdo:

pid=

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

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

Este arquivo informa ao stunnel o que ele precisa saber. Especificamente, você está dizendo a ele para não usar um arquivo pid, onde está o arquivo de certificado, qual versão de SSL usar, que deve ser executado em primeiro plano, onde deve registrar sua saída e que deve aceitar conexão na porta 8443 e transportá-los para a porta 8001. O último parâmetro (TIMEOUTclose) diz para fechar automaticamente a conexão após 1 segundo passar sem atividade.

Agora volte para o diretório do projeto Django (aquele com manage.py):

cd ..

Aqui, criaremos um script chamado runserver que executará o stunnel e dois servidores de desenvolvimento django (um para conexões normais e outro para conexões SSL):

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

Vamos decompô-lo, linha por linha:

  • Linha 1: inicia o stunnel e aponta para o arquivo de configuração que acabamos de criar. Isso faz com que o stunnel escute na porta 8443, envolva todas as conexões recebidas em SSL e as transmita para a porta 8001
  • Linha 2: inicia uma instância normal do servidor de execução do Django (na porta 8000)
  • Linha 3: inicia outra instância do servidor de execução do Django (na porta 8001) e a configura para tratar todas as conexões de entrada como se estivessem sendo realizadas usando HTTPS.

Torne o arquivo runscript que acabamos de criar executável com:

chmod a+x runserver

Agora, quando você quiser executar o servidor de desenvolvimento, execute apenas a ./runserverpartir do diretório do projeto. Para experimentar, basta apontar o navegador para http: // localhost: 8000 para tráfego HTTP normal e https: // localhost: 8443 para tráfego HTTPS. Observe que seu navegador quase definitivamente reclamará sobre o certificado usado e exigirá que você adicione uma exceção ou instrua explicitamente o navegador a continuar navegando. Isso ocorre porque você criou seu próprio certificado e o navegador não confia nele para dizer a verdade sobre ele. Isso é bom para o desenvolvimento, mas obviamente não servirá para a produção.

Infelizmente, na minha máquina, esse script do servidor de execução não sai bem quando pressiono Ctrl-C. Tenho que matar os processos manualmente - alguém tem alguma sugestão para consertar isso?

Obrigado à postagem de Michael Gile e à entrada do wiki de django-weave para o material de referência.

Evan Grim
fonte
3
Eu apenas tropecei nesta resposta. Algumas observações: você não precisa necessariamente executar uma instância de desenvolvimento separada em 8001, você também pode deixá-la se conectar à porta 8000. Se você deseja que o stunnel seja eliminado automaticamente, adicione uma função e uma armadilha de saída: kill_stunnel () { kill $ stunnel_pid} armadilha kill_stunnel saída stunnel4 stunnel / dev https & stunnel_pid = $ 1
Friek
2
A segunda instância é chamada com HTTPS = 1, o que significa que request.is_secure()irá relatar True. Se você não precisa disso, está certo - você pode apenas apontar o stunnel para uma única instância.
Evan Grim
Se você executar no modo stunnel fips não suportado .... adicione fips = no ao arquivo dev_https para desligá-lo
yeahdixon
2
Acabei de tentar fazer isso enquanto estou tentando configurar uma cópia de desenvolvimento de um trabalho de site em um projeto desenvolvido por outra pessoa, mas estou conseguindo "sslVersion = SSLv3": SSLv3 not supported.
HenryM
@Friek stunnel_pid=$1não funcionou para mim, mas stunnel_pid=$!funcionou. Como stunnel_pid=$1funcionou para você?
Utku
86

Eu recomendaria usar o pacote django-sslserver .

O pacote atual no PyPI suporta apenas a versão 1.5.5 do Django, mas um patch foi enviado via 5d4664c . Com esta correção, o sistema funciona bem e é uma solução bastante simples e direta para testar conexões https.

ATUALIZAÇÃO: Desde que postei minha resposta, o commit acima foi incorporado ao branch master e uma nova versão foi enviada ao PyPI. Portanto, não deve haver nenhuma necessidade de especificar o commit 5d4664c para essa correção específica.

Devonbleibtrey
fonte
5
Isso parece promissor - talvez eu precise atualizar a resposta aceita para esta questão. Alguém mais quer pesar?
Evan Grim
3
esta deve ser a resposta aceita, usada por um tempo em um projeto bastante complexo que simplesmente não funciona sem rodar em https e nunca teve problemas.
simone cittadini
2
Funciona bem ... Obrigado! :)
nidHi
5
Funciona a partir de Python 3.6.2 e Django 1.11.3.
Phoenix
2
Funciona a partir de Python 3.5 e Django 1.11
Hansel
64

Semelhante ao django-sslserver, você pode usar RunServerPlus do django-extensions

Ele tem dependências do Werkzeug (para que você tenha acesso ao excelente depurador Werkzeug) e pyOpenSSL (necessário apenas para o modo ssl) para instalar execute:

pip install django-extensions Werkzeug pyOpenSSL

Adicione-o ao INSTALLED_APPS no arquivo settings.py do seu projeto:

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

Em seguida, você pode executar o servidor no modo SSL com:

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

Isso criará um arquivo cert em /tmp/cert.crte um arquivo de chave no /tmp/cert.keyqual poderá ser reutilizado para sessões futuras.

Há um monte de coisas extras incluídas nas extensões django que você pode achar úteis, então vale a pena dar uma olhada rápida na documentação.

Djsutho
fonte
2
Na verdade, a melhor resposta para Django 1.6+, uma vez que django-sslserver não suporta auto-reload para a nova versão
Zat42
A melhor resposta para depurar + ativar SSL.
Yuda Prawira
Eu me pergunto por que ele não funciona no aplicativo docker em contêineres
Roel
@Roel fez uma tentativa rápida e parece funcionar para um aplicativo hello world. pode ser que sua imagem de base não tenha dependências necessárias (por exemplo, se você usar -alpine) ou talvez você precise abrir seu intervalo de IP, por exemplo./manage.py runserver_plus --cert /tmp/cert 0.0.0.0:8000
djsutho
FileNotFoundError: [Errno 2] Nenhum arquivo ou diretório: '/tmp\\cert.crt'
Mark Anthony Libres
38

apenas instale

sudo pip install django-sslserver

incluir sslserver em aps instalados

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

agora você pode correr

 python manage.py runsslserver 0.0.0.0:8888
Ryabchenko Alexander
fonte
2
A solução mais limpa!
SexyBeast
de fato, uma solução limpa, mas por algum motivo, é muito lenta
Bhanu Tez
Hmm, o Chrome está avisando que o certificado é inválido.
zerohedge
@zerohedge é apenas para desenvolvimento, então não importa.
Sharpless512
isso é muito elegante - mas existe alguma solução para usar isso para testar conexões seguras? por exemplo, se você deseja testar a API Graph do Facebook? developers.facebook.com/docs/graph-api/webhooks#setup
frednikgohar
14

Inscreva-se em https://ngrok.com/ . Você pode usar https para testar. Isso pode ajudar as pessoas que desejam apenas testar https rapidamente.

Neil
fonte
6
Para um teste rápido, esta é uma ótima solução. E eu não tive que me cadastrar para nada, apenas baixei e executei ./ngrok http 8000, 8000 é minha porta localhost.
GavKilbride
4

Para quem procura uma versão em primeiro plano da opção stunnel para fins de depuração:

stunnel.pem é um certificado gerado como na resposta mais votada de Evan Grimm.

Ouça em todas as interfaces locais na porta 443 e encaminhe para a porta 80 no localhost

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

sudo só é necessário para portas de entrada (-d [host:] porta) abaixo de 1024

Micheal Lunny
fonte
4
  1. Instale o ngrok. link de download: https://ngrok.com/download
  2. Emita o seguinte comando no terminal

    ngrok http 8000

Isso iniciará a sessão do ngrok. Ele listará dois urls. Um é mapeado para http: // localhost: 8000 . O segundo é mapeado para https: // localhost: 8000 . Por favor, verifique a imagem abaixo. Use qualquer um dos url. Ele será mapeado para seu servidor local.

captura de tela de amostra da sessão ngrok

ABN
fonte
A maneira mais fácil de fazer isso, mas lembre-se de colocar o novo url https emallowed_host
Roel
2

Isso pode ser feito em uma linha com socat:

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

, em que 8443 é uma porta para ouvir conexões HTTPS de entrada, server.pem é um certificado de servidor autoassinado e localhost: 8000 é um servidor HTTP de depuração iniciado normalmente.

Mais detalhes: http://www.dest-unreach.org/socat/doc/socat-openssltunnel.html

uri.z
fonte
0

Lide com SSL / TLS com um proxy como Nginx em vez de Django. O Nginx pode ser configurado para escutar na porta 443 e, em seguida, encaminhar solicitações para o servidor de desenvolvimento Django (normalmente http://127.0.0.1:8000). Uma configuração Nginx para isso pode ser semelhante a esta:

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

Você também vai precisar para mapear django-dev.localhosta 127.0.0.1e adicione django-dev.localhosta ALLOWED_HOSTSno settings.py. No Linux, você precisará adicionar a seguinte linha a /etc/hosts:

127.0.0.1   django-dev.localhost

Então, você poderá acessar seu site de desenvolvimento acessando https://django-dev.localhostem seu navegador (você precisará ignorar o aviso de segurança do navegador).

cinquenta cartões
fonte