我如何使用' runserver'来尽可能轻松地使用Django测试https连接?

时间:2011-11-05 20:38:52

标签: django ssl https

我有一个使用“安全”cookie的应用程序,并希望测试它的功能,而无需设置复杂的SSL启用开发服务器。有没有办法做到这一点,因为我可以使用./manage.py runserver测试非加密请求?

9 个答案:

答案 0 :(得分:103)

它不像内置的开发服务器那样简单,但是使用stunnel作为浏览器和开发服务器之间的SSLifying中间人并不太难。 Stunnel允许您在计算机上设置一个轻量级服务器,该服务器接受已配置端口上的连接,使用SSL包装它们,并将它们传递给其他服务器。我们将使用它来打开一个stunnel端口(8443),并将它收到的任何流量传递给Django runserver实例。

首先你需要stunnel,它可以是downloaded here,也可以由你的平台的包系统提供(例如:apt-get install stunnel)。我将使用stunnel的第4版(例如:Ubuntu上的/usr/bin/stunnel4),版本3也可以使用,但是有不同的配置选项。

首先在Django项目中创建一个目录,以保存必要的配置文件和SSLish。

mkdir stunnel
cd stunnel

接下来,我们需要创建一个用于SSL通信的本地证书和密钥。为此,我们转向openssl。

创建密钥:

openssl genrsa 1024 > stunnel.key

创建使用此密钥的证书(这将询问您将包含在证书中的大量信息 - 只需回答任何对您感觉良好的信息):

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

现在将这些组合成一个stunnel用于SSL通信的文件:

cat stunnel.key stunnel.cert > stunnel.pem

为stunnel创建一个名为dev_https的配置文件,其中包含以下内容:

pid=

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

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

此文件告诉stunnel它需要知道什么。具体来说,你告诉它不要使用pid文件,证书文件在哪里,使用什么版本的SSL,它应该在前台运行,它应该记录它的输出,以及它应该接受端口上的连接8443并将它们连接到端口8001.最后一个参数(TIMEOUTclose)告诉它在1秒钟后没有活动时自动关闭连接。

现在回到Django项目目录(其中包含manage.py的目录):

cd ..

这里我们将创建一个名为runserver的脚本,它将运行stunnel和两个django开发服务器(一个用于普通连接,一个用于SSL连接):

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

让我们逐行分解:

  • 第1行:启动stunnel并将其指向我们刚刚创建的配置文件。这有stunnel监听端口8443,包装它在SSL中接收的任何连接,并将它们传递到端口8001
  • 第2行:启动正常的Django runserver实例(在端口8000上)
  • 第3行:启动另一个Django runserver实例(在端口8001上)并将其配置为将所有传入连接视为使用HTTPS执行它们。

使我们刚创建的脚本文件可执行:

chmod a+x runserver

现在,当您想要运行开发服务器时,只需从项目目录中执行./runserver即可。要试用它,只需将浏览器指向http://localhost:8000以获取正常的HTTP流量,并将https://localhost:8443指向HTTPS流量。请注意,您的浏览器几乎肯定会抱怨所使用的证书,并要求您添加例外或明确指示浏览器继续浏览。这是因为您创建了自己的证书,浏览器不信任它是否说实话。这对于开发来说很好,但显然不会将其用于生产。

不幸的是,在我的机器上,当我按下Ctrl-C时,这个runserver脚本不能很好地退出。我必须手动杀死进程 - 任何人都有建议解决这个问题吗?

感谢Michael Gile的post和django-weave的wiki entry作为参考资料。

答案 1 :(得分:71)

我建议使用django-sslserver包。

PyPI上的当前包仅支持Django 1.5.5版,但已通过5d4664c提交了补丁。通过此修复,系统运行良好,是一种非常简单直接的测试https连接的解决方案。

更新: 自从我发布了我的答案后,上面的提交已经merged进入主分支,并且新的release已被推送到PyPI。因此,不应该为该特定修复指定5d4664c提交。

答案 2 :(得分:52)

与django-sslserver类似,您可以使用RunServerPlus中的django-extensions

它依赖于Werkzeug(因此您可以访问优秀的Werkzeug调试器)和pyOpenSSL(仅适用于ssl模式),因此要安装run:

pip install django-extensions Werkzeug pyOpenSSL

将它添加到项目settings.py文件中的INSTALLED_APPS:

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

然后您可以使用以下命令在ssl模式下运行服务器:

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

这将在/tmp/cert.crt创建一个证书文件,在/tmp/cert.key创建一个密钥文件,然后可以在以后的会话中重复使用。

django-extensions中包含一些额外的东西,你可能会发现它们有用,所以值得快速浏览文档。

答案 3 :(得分:12)

注册https://ngrok.com/。您可以使用https进行测试。这可能会帮助那些只想快速测试https的人。

答案 4 :(得分:10)

只需安装

adapter.addFrag(MyFragment.newInstance(model), getString(R.string.sep_prep_base));

在已安装的aps中包含sslserver

sudo pip install django-sslserver

现在您可以运行

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

答案 5 :(得分:4)

对于那些寻找用于调试目的的stunnel选项的预定版本的人:

stunnel.pem是在Evan Grimm的最高投票答案中生成的证书。

侦听端口443上的所有本地接口,并转发到localhost上的端口80

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

sudo仅对1024

下的传入端口(-d [host:] port)是必需的

答案 6 :(得分:4)

一种方法是使用ngrok。

  1. 安装ngrok。 下载链接:https://ngrok.com/download

  2. 在终端上发出以下命令

    ngrok http 8000
    

它将开始ngrok会话。它将列出两个URL。一个映射到http:// localhost:8000。第二个映射到https:// localhost:8000。请检查以下屏幕截图。使用任一网址。它将映射到您的本地服务器。

sample ngrok session screenshot


第二种方法与@EvanGrim提供的解决方案相同。链接-https://stackoverflow.com/a/8025645/9384511

如果您仅需要几次测试https url,则首选第一种方法。但是,如果您的要求说https是强制性的,那么遵循第二种方法会更好。 我遇到了@EvanGrim解决方案的以下问题

  1. 通过请求访问https URL时,您将获得subAltNames 缺少警告。这应该不是问题。您的网址应该可以 很好。
  2. 您将无法通过android volley访问https网址。它会 引发错误-您的IP或本地主机未通过验证。就像是 那。

我通过在ssl证书中添加subAltname解决了这些问题。下面是我在没有上述两个问题的情况下运行本地https服务器的步骤。

  1. 安装通道。使用的stunnel版本为version4(/ usr / bin / stunnel4)用于ubuntu执行

     sudo apt-get install stunnel
    
  2. 在Django项目中创建目录路径。

  3. 从/etc/ssl/openssl.cnf或/usr/lib/ssl/openssl.cnf复制openssl.cnf到通道。除非您知道自己在做什么,否则请避免直接编辑它们。

    1. 搜索[req]或[req]部分。在req部分中设置

       x509_extensions = v3_ca 
       req_extensions = v3_req 
      

      x509_extensions和req_extensions应该存在。如果没有,请添加它。如果有评论,请取消评论。

    2. 搜索[v3_req]部分。在此部分添加

       subjectAltName = @alt_names
      
    3. 搜索[v3_ca]部分。在此部分添加

       subjectAltName = @alt_names
      
    4. 我们需要添加一个新部分alt_names。可以在任何地方添加。我在[v3_ca]部分之后添加了。 对于本地主机和您的IP地址,请添加以下内容:

       [alt_names]
       DNS.1 = localhost
       IP.1 = x.x.x.x
       IP.2 = 127.0.0.1
      
  4. 要创建密钥,请执行

     openssl genrsa 1024 > stunnel.key
    
  5. 要创建DER编码的证书,请执行第一条命令或第二条命令

    1. 如果您直接编辑了/etc/ssl/openssl.cnf或/usr/lib/ssl/openssl.cnf

       openssl req -new -x509 -nodes -sha1 -days 365 -key stunnel.key > stunnel.cert
      
    2. 如果已在stunnel目录中复制了openssl.cnf。

       openssl req -new -x509 -nodes -sha256 -days 365 -key stunnel.key -config openssl.cnf > stunnel.cert
      
  6. 要创建PEM证书,请执行。

     cat stunnel.key stunnel.cert > stunnel.pem
    
  7. 为带有以下内容的内容的隧道创建一个名为dev_https.config的配置文件。

     #not to use pid
     pid=
     #path of certificate file
     cert = stunnel/stunnel.pem
     #version of SSL to use
     sslVersion = TLSv1.1
     foreground = yes
     #log output path
     output = stunnel.log
    
     [https]
     #listen on port 8443
     accept=8443
     #tunnel the connection to port 8001
     connect=8001
     # and close connection automatically after one second
     TIMEOUTclose=1
    

    请注意sslVersion基于python解释器使用的OpenSSL版本。我的是OpenSSL 1.1.1。对于此版本,请使用TLSv1.1。找出您的openssl版本并添加相应的版本。 您可以通过执行

    来找出OpenSSL版本
     python -c "import ssl; print(ssl.OPENSSL_VERSION)"
    
  8. 创建一个名为runserver的脚本,并添加以下内容。该脚本应与manage.py位于同一目录中 该脚本将运行两个stunnel和两个django环境。一个用于http连接,一个用于https连接。 运行服务器不能干净退出的问题(如Evan所述)通过陷阱语句解决,该陷阱语句调用了清理功能。

     stunnel4 stunnel/dev_https.config &
     stunnel_pid=$!
     echo "stunnel pid: $stunnel_pid"
     python manage.py runserver 0.0.0.0:8000 &
     py_server_bg=$!
     echo "BG py server pid: $py_server_bg"
     HTTPS=1 python manage.py runserver 0.0.0.0:8001
    
     function cleanup()
     {
       echo "Cleaning up"
       kill $stunnel_pid
       kill $py_server_bg
       echo "Cleaned"
     }
    
     trap cleanup EXIT
    
  9. 执行

     chmod a+x runserver
    
  10. 从您的Django项目执行

    ./runserver
    
  11. 现在,如果您执行python请求命令,则不会显示subjectAltNames缺少警告。另外,您的android volley https请求也可以正常执行。

    data = {'login_id':'someid'}
    headers = {'content-type': 'application/json'}
    url = "https://localhost:8443/myauth/check-id/"
    r=requests.post(url, data=json.dumps(data), headers=headers,verify='stunnel/stunnel.pem')
    

我要感谢@EvanGrim提供的解决方案。感谢@ Friek,@ Utku和@dr。 Sybren。根据他们的评论,我实现了清理功能。

答案 7 :(得分:1)

可以使用socat在一行中完成:

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

,其中8443是侦听传入HTTPS连接的端口,server.pem是自签名服务器证书,localhost:8000是像往常一样启动的调试HTTP服务器。

更多详情:http://www.dest-unreach.org/socat/doc/socat-openssltunnel.html

答案 8 :(得分:0)

使用代理(例如Nginx)而不是Django处理SSL / TLS。可以将Nginx设置为侦听端口443,然后将请求转发到Django开发服务器(通常为http://127.0.0.1:8000)。 Nginx的配置可能如下所示:

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

您还需要将django-dev.localhost映射到127.0.0.1并将django-dev.localhost添加到ALLOWED_HOSTS中的settings.py。在Linux上,您需要将以下行添加到/etc/hosts

127.0.0.1   django-dev.localhost

然后,您可以通过在浏览器中转到https://django-dev.localhost来访问您的开发人员站点(您将需要绕过浏览器的安全警告)。