How can I test https connections with Django as easily as I can non-https connections using 'runserver'?

后端 未结 9 921
生来不讨喜
生来不讨喜 2020-11-28 17:55

I have an application that uses \"secure\" cookies and want to test it\'s functionality without needing to set up a complicated SSL enabled development server. Is there any

相关标签:
9条回答
  • 2020-11-28 18:00

    For those looking for a foregrounded version of the stunnel option for debugging purposes:

    stunnel.pem is a certificate generated as in Evan Grimm's top voted answer.

    Listen on all local interfaces on port 443 and forward to port 80 on localhost

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

    sudo is only necessary for incoming ports (-d [host:]port) under 1024

    0 讨论(0)
  • 2020-11-28 18:02

    Similar to django-sslserver you could use RunServerPlus from django-extensions

    It has dependencies on Werkzeug (so you get access to the excellent Werkzeug debugger) and pyOpenSSL (only required for ssl mode) so to install run:

    pip install django-extensions Werkzeug pyOpenSSL
    

    Add it to INSTALLED_APPS in your projects settings.py file:

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

    Then you can run the server in ssl mode with:

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

    This will create a cert file at /tmp/cert.crt and a key file at /tmp/cert.key which can then be reused for future sessions.

    There is a bunch of extra stuff included in django-extensions that you may find of use so it is worth having a quick flick through the docs.

    0 讨论(0)
  • 2020-11-28 18:08

    One way is using ngrok.

    1. Install ngrok. download link: https://ngrok.com/download

    2. Issue following command on terminal

      ngrok http 8000
      

    It will start ngrok session. It will list two urls. One is mapped to http://localhost:8000. Second is mapped to https://localhost:8000. Please check the screenshot below. Use either url. It will map to your local server.


    Second method is as per the the solution provided by @EvanGrim. Link - https://stackoverflow.com/a/8025645/9384511

    First method is preferred if you need to test https url just couple of times. But if your requirement says https is mandatory then it would be better if you follow second method. I faced following issues with @EvanGrim solution

    1. When accessing https url via requests, you will get subAltNames missing warning. This should not be a problem. Your url should work fine.
    2. You will not be able to access https url via android volley. It will throw error - your ip or localhost is not verified. Something like that.

    I solved these issues by adding subAltname to ssl certificate. Below is the steps I followed to run a local https server without the above two issues.

    1. Install stunnel. stunnel version used is version4(/usr/bin/stunnel4) For ubuntu execute

       sudo apt-get install stunnel
      
    2. Create directory stunnel in your Django Project.

    3. Copy openssl.cnf from /etc/ssl/openssl.cnf or /usr/lib/ssl/openssl.cnf to stunnel. Avoid editing them directly unless you know what you are doing.

      1. Search for [ req ] or [req] section.In req section set

         x509_extensions = v3_ca 
         req_extensions = v3_req 
        

        x509_extensions and req_extensions should be present. If not, add it. If commented, uncomment it.

      2. Search for [v3_req] section. In this section add

         subjectAltName = @alt_names
        
      3. Search for [v3_ca] section. In this section add

         subjectAltName = @alt_names
        
      4. We need to add a new section alt_names. This can be added any where. I added after [v3_ca] section. For local host and your ip address add as follows:

         [alt_names]
         DNS.1 = localhost
         IP.1 = x.x.x.x
         IP.2 = 127.0.0.1
        
    4. To create key execute

       openssl genrsa 1024 > stunnel.key
      
    5. To create DER encoded certificate execute either first or second command

      1. If you have directly edited /etc/ssl/openssl.cnf or /usr/lib/ssl/openssl.cnf

         openssl req -new -x509 -nodes -sha1 -days 365 -key stunnel.key > stunnel.cert
        
      2. If you have made copy of openssl.cnf in stunnel directory.

         openssl req -new -x509 -nodes -sha256 -days 365 -key stunnel.key -config openssl.cnf > stunnel.cert
        
    6. To create PEM ecoded certificate execute.

       cat stunnel.key stunnel.cert > stunnel.pem
      
    7. Create a config file for stunnel called dev_https.config with the following contents.

       #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
      

      Please note sslVersion is based on OpenSSL version used by python interpreter. Mine is OpenSSL 1.1.1. For this version use TLSv1.1. Find out your openssl version and add corresponding version. You can find out the OpenSSL version by executing

       python -c "import ssl; print(ssl.OPENSSL_VERSION)"
      
    8. Create a script called runserver and add below contents. This script should reside in same directory as manage.py This script will run two stunnel and two django environment. One for http connections and one for https connections. The issue of runserver not exiting cleanly(As mentioned by Evan) is solved by trap statement in which cleanup function is called.

       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. Execute

       chmod a+x runserver
      
    10. From you django project execute

      ./runserver
      
    11. Now if you execute a python requests command, subjectAltNames missing warning will not be displayed. Also your android volley https request will execute fine.

      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')
      

    I would like to thank @EvanGrim for the solution. And Thanks to @Friek, @Utku and @dr. Sybren. Based on their comments I implemented cleanup function.

    0 讨论(0)
  • 2020-11-28 18:15

    It's not as simple as the built in development server, but it's not too hard to get something close using stunnel as an SSLifying middleman between your browser and the development server. Stunnel allows you to set up a lightweight server on your machine that accepts connections on a configured port, wraps them with SSL, and passes them along to some other server. We'll use this to open a stunnel port (8443) and pass along any traffic it receives to a Django runserver instance.

    First you'll need stunnel which can be downloaded here or may be provided by your platform's package system (e.g.: apt-get install stunnel). I'll be using version 4 of stunnel (e.g.: /usr/bin/stunnel4 on Ubuntu), version 3 will also work, but has different configuration options.

    First create a directory in your Django project to hold the necessary configuration files and SSLish stuff.

    mkdir stunnel
    cd stunnel
    

    Next we'll need to create a local certificate and key to be used for the SSL communication. For this we turn to openssl.

    Create the key:

    openssl genrsa 1024 > stunnel.key
    

    Create the certificate that uses this key (this will ask you a bunch of information that will be included in the certficate - just answer with whatever feels good to you):

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

    Now combine these into a single file that stunnel will use for its SSL communication:

    cat stunnel.key stunnel.cert > stunnel.pem
    

    Create a config file for stunnel called dev_https with the following contents:

    pid=
    
    cert = stunnel/stunnel.pem
    sslVersion = SSLv3
    foreground = yes
    output = stunnel.log
    
    [https]
    accept=8443
    connect=8001
    TIMEOUTclose=1
    

    This file tells stunnel what it needs to know. Specifically, you're telling it not to use a pid file, where the certificate file is, what version of SSL to use, that it should run in the foreground, where it should log its output, and that it should accept connection on port 8443 and shuttle them along to port 8001. The last parameter (TIMEOUTclose) tells it to automatically close the connection after 1 second has passed with no activity.

    Now pop back up to your Django project directory (the one with manage.py in it):

    cd ..
    

    Here we'll create a script named runserver that will run stunnel and two django development servers (one for normal connections, and one for SSL connections):

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

    Let's break this down, line-by-line:

    • Line 1: Starts stunnel and point it to the configuration file we just created. This has stunnel listen on port 8443, wrap any connections it receives in SSL, and pass them along to port 8001
    • Line 2: Starts a normal Django runserver instance (on port 8000)
    • Line 3: Starts another Django runserver instance (on port 8001) and configures it to treat all incoming connections as if they were being performed using HTTPS.

    Make the runscript file we just created executable with:

    chmod a+x runserver
    

    Now when you want to run your development server just execute ./runserver from your project directory. To try it out, just point your browser to http://localhost:8000 for normal HTTP traffic, and https://localhost:8443 for HTTPS traffic. Note that you're browser will almost definitely complain about the certificate used and require you to add an exception or otherwise explicitly instruct the browser to continue browsing. This is because you created your own certificate and it isn't trusted by the browser to be telling the truth about who it is. This is fine for development, but obviously won't cut it for production.

    Unfortunately, on my machine this runserver script doesn't exit out nicely when I hit Ctrl-C. I have to manually kill the processes - anyone have a suggestion to fix that?

    Thanks to Michael Gile's post and django-weave's wiki entry for the reference material.

    0 讨论(0)
  • 2020-11-28 18:15

    Handle SSL/TLS with a proxy such as Nginx rather than Django. Nginx can be set up to listen on port 443 and then forward requests to your Django dev server (typically http://127.0.0.1:8000). An Nginx configuration for this might look like the following:

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

    You'll also need to map django-dev.localhost to 127.0.0.1 and add django-dev.localhost to ALLOWED_HOSTS in settings.py. On Linux, you'll need to add the following line to /etc/hosts:

    127.0.0.1   django-dev.localhost
    

    You'll then be able to reach your dev site by going to https://django-dev.localhost in your browser (you will need to bypass your browser's security warning).

    0 讨论(0)
  • 2020-11-28 18:17

    just install

    sudo pip install django-sslserver
    

    include sslserver in installed aps

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

    now you can run

     python manage.py runsslserver 0.0.0.0:8888
    
    0 讨论(0)
提交回复
热议问题