【问题标题】:How can I test https connections with Django as easily as I can non-https connections using 'runserver'?如何像使用“runserver”的非 https 连接一样轻松地测试与 Django 的 https 连接?
【发布时间】:2011-12-22 19:32:30
【问题描述】:

我有一个使用“安全”cookie 的应用程序,并且想要测试它的功能,而无需设置复杂的启用 SSL 的开发服务器。有什么方法可以做到这一点,就像我可以使用 ./manage.py runserver 测试非加密请求一样简单?

【问题讨论】:

  • 不能只指定runserver 443让服务器运行在443端口吗?
  • @Furbeenator:不幸的是,这只会使服务器 HTTP 在 443 上运行,我需要的是一个正在运行的实际 SSL 服务器。

标签: django ssl https


【解决方案1】:

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

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

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

mkdir stunnel
cd stunnel

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

创建密钥:

openssl genrsa 2048 > 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 并将其指向我们刚刚创建的配置文件。这在端口 8443 上进行了 stunnel 侦听,将接收到的任何连接包装在 SSL 中,并将它们传递到端口 8001
  • 第 2 行:启动一个普通的 Django 运行服务器实例(在端口 8000 上)
  • 第 3 行:启动另一个 Django runserver 实例(在端口 8001 上)并将其配置为将所有传入连接视为使用 HTTPS 执行。

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

chmod a+x runserver

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

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

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

【讨论】:

  • 我只是偶然发现了这个答案。备注:不一定要在8001上运行单独的开发实例,也可以让它连接到8000端口。如果要自动杀死stunnel,添加一个函数和一个退出陷阱:kill_stunnel(){杀死 $stunnel_pid } 陷阱 kill_stunnel 退出 stunnel4 stunnel/dev https & stunnel_pid=$1
  • 第二个实例使用 HTTPS=1 调用,这意味着request.is_secure() 将报告True。如果您不需要,那么您是对的 - 您可以将 stunnel 指向单个实例。
  • 如果您遇到不支持的 stunnel fips 模式 .... 在 dev_https 文件中添加 fips = no 以将其关闭
  • 我刚刚尝试过这个,因为我正在尝试为其他人开发的项目设置网站工作的开发副本,但我收到了"sslVersion = SSLv3": SSLv3 not supported
  • @HenryM 使用 TLSv1.2 而不是过时的 SSLv3。我已经编辑了答案以说明 SSLv3 的弃用。
【解决方案2】:

我建议使用django-sslserver 包。

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

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

【讨论】:

  • 这看起来很有希望 - 我可能需要更新这个已接受的答案。还有人想参与吗?
  • 这应该成为公认的答案,在一个相当复杂的项目中使用了一段时间,如果没有在 https 上运行就无法工作并且从来没有问题。
  • 效果很好...谢谢!:)
  • 适用于 Python 3.6.2 和 Django 1.11.3。
  • 适用于 Python 3.5 和 Django 1.11
【解决方案3】:

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

它依赖于 Werkzeug(因此您可以访问出色的 Werkzeug 调试器)和 pyOpenSSL(仅 ssl 模式需要),因此安装运行:

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 中包含许多额外的东西,您可能会发现它们很有用,因此值得快速浏览一下文档。

【讨论】:

  • 实际上是 Django 1.6+ 的最佳答案,因为 django-sslserver 不支持新版本的自动重新加载
  • 调试+激活SSL的最佳答案。
  • 我想知道为什么它在 docker 容器化应用程序中不起作用
  • @Roel 快速尝试了一下,它似乎适用于 hello world 应用程序。可能是您的基础映像没有必需的依赖项(例如,如果您使用 -alpine),或者您可能需要打开 IP 范围,例如./manage.py runserver_plus --cert /tmp/cert 0.0.0.0:8000
  • @MarkAnthonyLibres 你跑什么来得到那个错误?你在用窗户吗?您是否尝试过使用不同的路径,例如./manage.py runserver_plus --cert foo
【解决方案4】:

只需安装

sudo pip install django-sslserver

在已安装的应用程序中包含 sslserver

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

现在你可以运行了

 python manage.py runsslserver 0.0.0.0:8888

【讨论】:

  • 最干净的解决方案!
  • 确实是一个干净的解决方案,但由于某种原因,它很慢
  • 嗯,Chrome 发出了证书无效的警告。
  • @zerohedge 只是为了开发,所以没关系。
  • 这非常优雅——但是有没有什么解决方案可以使用它来测试安全连接?例如,如果您想针对 Facebook Graph API 进行测试? developers.facebook.com/docs/graph-api/webhooks#setup
【解决方案5】:

注册https://ngrok.com/。可以使用 https 进行测试。这可能对只想快速测试 https 的人有所帮助。

【讨论】:

  • 对于快速测试,这是一个很好的解决方案。而且我不需要注册任何东西,只需下载并运行 ./ngrok http 8000, 8000 是我的 localhost 端口。
  • 这是最好最流畅的解决方案。
  • 如果ngrok 的免费限制过于严格,而您的服务器正在运行,您可以roll your own ngrok
【解决方案6】:

一种方法是使用 ngrok。

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

  2. 在终端发出以下命令

    ngrok http 8000
    

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


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

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

  1. 通过请求访问https url时,会得到subAltNames 缺少警告。这应该不是问题。你的网址应该有效 很好。
  2. 您将无法通过 android volley 访问 https url。它会 抛出错误 - 您的 ip 或 localhost 未验证。就像是 那个。

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

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

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

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

    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. 为 stunnel 创建一个名为 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 连接。 runserver 不干净退出的问题(如 Evan 所说)通过调用 cleanup 函数的 trap 语句解决。

     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 requests 命令,将不会显示 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。西布伦。基于他们的 cmets 我实现了清理功能。

【讨论】:

  • 最简单的方法,但记得将新的 https url 放到 allowed_host
  • 那个 HTTPS=1 环境变量。那是在做什么,并且在任何地方都有记录吗?谷歌搜索让我无处可去,但我不确定它是一个未记录的 django 功能还是只是一个 ungoogle 名称。
【解决方案7】:

对于那些正在寻找用于调试目的的 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)是必需的

【讨论】:

    【解决方案8】:

    可以用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

    【讨论】:

      【解决方案9】:

      使用 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 并在settings.py 中将django-dev.localhost 添加到ALLOWED_HOSTS。在 Linux 上,您需要将以下行添加到 /etc/hosts

      127.0.0.1   django-dev.localhost
      

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

      【讨论】:

        【解决方案10】:

        前往sslforfree.com并下载证书文件

        download 3246328748324897329847324234.txt file for verify
        

        你需要在views.py中添加这个

        from django.http import HttpResponse
        
        def read_file(request):
            f = open('7263713672163767218367687767.txt', 'r')
            file_content = f.read()
            f.close()
            return HttpResponse(file_content, content_type="text/plain")
        

        之后 添加

        urls.py
        

            path('.well-known/pki-validation/', read_file)
        

        安装

        pip install django-extensions
        pip install pyOpenSSL
        pip install werkzeug
        
        ./manage.py runserver_plus 0:443 --cert-file certificate.crt  --key-file private.key
        

        【讨论】:

          【解决方案11】:

          我有一个非常简单的解决方案,只需按照以下步骤操作,您就可以在 https:// 安全服务器上运行您的 django 项目/应用程序。

          step.1 在您的系统上安装 openssl。您可以在https://slproweb.com/products/Win32OpenSSL.html 获取安装的可执行文件。我推荐你安装 Win64 OpenSSL v1.1.1L (version) 它比 3.0.0 稳定

          成功安装后的第 2 步导航到我们示例中的 C:\Program Files\OpenSSL-Win64\bin。你可以导航到你安装了openssl的安装目录,在这里你可以找到openssl.exe以管理员身份运行它。

          step.3 输入以下命令开始生成证书和私钥: req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout privateKey.key -out certificate.crt

          第 4 步:然后您将被提示输入适用的专有名称 (DN) 信息,总共七个字段,如下面的屏幕截图所示:

          步骤 5:完成后,您将在 \OpenSSL\bin\ 目录下找到创建的 certificate.crt 和 privateKey.key 文件,如下所示

          第 6 步:在您的系统中安装 django-sslserver。

          stpe 7:在您的 IDLE 终端上执行以下命令: python manage.py 运行slserver --certificate C:/Program Files/OpenSSL-Win64/bin/cer tificate.crt --key C:/Program Files/OpenSSL-Win64/bin/privateKey.key 127.0.0.1:8000

          恭喜你的 django 项目现在在 https 上运行。

          希望对你有帮助,如果你遇到任何困难,请随时询问。

          【讨论】:

            【解决方案12】:

            尝试向this answer 添加评论,他在其中询问有关终止进程的问题,但 cmets 中的代码格式有限。这是我修改后的 runserver.bash

            #!/bin/bash 
            
            # Script to kill previous instances of dev servers,
            # then start the 2 dev servers, one of which is https.
            #
            
            cd "$(dirname "$0")"
            echo $PWD
            
            . bin/activate
            
            if [[ "$1" =~ "kill" ]]; then
                if [[ -n `ps -ef | egrep 'python manage.py runserver [1-9,\.]*' | grep -v grep | awk '{ print $2}'`  ]]; then
                    kill -15 `ps -ef | egrep 'python manage.py runserver [1-9,\.]*' | grep -v grep | awk '{ print $2}'`
                fi
            else
                if [[ -n `ps -ef | egrep 'python manage.py runserver [1-9,\.]*' | grep -v grep | awk '{ print $2}'`  ]]; then
                    kill -15 `ps -ef | egrep 'python manage.py runserver [1-9,\.]*' | grep -v grep | awk '{ print $2}'`
                fi
                if [[ -z `ps -ef | egrep 'stunnel4 stunnel/dev_https' | grep -v grep | awk '{ print $2}'` ]]; then
                    stunnel4 stunnel/dev_https &
                fi
                python manage.py runserver 192.168.1.183:8006 &
                HTTPS=1 python manage.py runserver 192.168.1.183:8001
            fi
            

            【讨论】:

              【解决方案13】:

              根据 Ryabchenko Alexander 的回答,这就是我在 Django 中进行本地测试的方式:

              token_url = '{}/o/token/'.format(settings.BOQ_APP_URL)
              oauth = OAuth2Session(
                 client=LegacyApplicationClient(client_id=settings.BOQ_APP_CLIENT_ID),
              )
              
              # disable cert verification for local tests
              if settings.DEBUG:
                  oauth.verify = False
              
              token = oauth.fetch_token(
                 token_url=token_url,
                 username=settings.BOQ_APP_USERNAME,
                 password=settings.BOQ_APP_PASSWORD,
                 client_secret=settings.BOQ_APP_CLIENT_SECRET,
              )
              
              print(token)
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2013-02-13
                • 2020-10-24
                • 2014-03-08
                相关资源
                最近更新 更多