How to implement HTTPS using Python + flask

Time:2021-8-4

Summary:In general, there is plaintext transmission of request information in HTTP, which is easy to be intercepted by eavesdropping; The integrity of the data is not verified and is easy to be tampered with; The identity of the other party is not verified, and there is a risk of impersonation. How to solve these problems?

This article is shared from Huawei cloud community《How to implement HTTPS using Python + flask》, original author: snher.

1、 Why use HTTPS

There are the following problems in general http: the request information is transmitted in plaintext, which is easy to be intercepted by eavesdropping; The integrity of the data is not verified and is easy to be tampered with; The identity of the other party is not verified, and there is a risk of impersonation.

What are the advantages of HTTPS?

1. Use HTTPS to authenticate users and servers to ensure that data is sent to the correct clients and servers.

2. HTTPS is a network protocol built by SSL + HTTP protocol for encrypted transmission and identity authentication. It is safer than HTTP protocol, which can prevent data from being stolen and changed during transmission and ensure data integrity.

3. HTTPS is the most secure solution under the current architecture. Although it is not absolutely secure, it greatly increases the cost of man in the middle attack.

2、 What is the certificate in HTTPS

How to implement HTTPS using Python + flask
CA: certificate authority, similar to the state exit entry administration, issues passports to others; It is also similar to the State Administration for Industry and commerce, which issues business licenses to companies and enterprises. It has two main properties:

  • CA itself is trusted and internationally recognized;
  • Issue certificates to his trusted applicants. As with passport handling, to determine your legal identity, you can’t be a criminal or a rebel. Of course, you need to be charged a protection fee, and Ca can revoke your certificate at any time.

What is the relationship between CA’s certificate ca.crt and SSL server’s certificate server.crt?

  • The SSL server generates a private key / public key pair, server.key/server.pub. Server.pub generates a request file server.req. The request file contains some information about the server, such as domain name / applicant / public key, etc.
  • The server submits the request file server.req to the ca. after the CA verifies the identity, it will encrypt the ca.key and the request file to generate server.crt. Since ca.key and ca.crt are a pair, ca.crt can decrypt server.crt.
  • In practical application: if the SSL client wants to verify the SSL server, the SSL server must pass its certificate server.crt to the client. Then the client uses ca.crt to verify the legitimacy of the server.crt. If it is a phishing website, CA will not issue a legal server.crt certificate to it. In this way, the client will fail to verify with ca.crt.

3、 Generate certificate and key

Shell script

#!/bin/bash

PROJECT_NAME="https Project"

# Generate the openssl configuration files.
cat > ca_cert.conf << EOF
[ req ]
distinguished_name     = req_distinguished_name
prompt                 = no

[ req_distinguished_name ]
 O                      = $PROJECT_NAME Certificate Authority
EOF

cat > server_cert.conf << EOF
[ req ]
distinguished_name     = req_distinguished_name
prompt                 = no

[ req_distinguished_name ]
 O                      = $PROJECT_NAME
 CN                     = 
EOF

cat > client_cert.conf << EOF
[ req ]
distinguished_name     = req_distinguished_name
prompt                 = no

[ req_distinguished_name ]
 O                      = $PROJECT_NAME Device Certificate
 CN                     = 
EOF

mkdir ca
mkdir server
mkdir client

#Generate private key
openssl genrsa -out ca.key 1024
openssl genrsa -out server.key 1024
openssl genrsa -out client.key 1024

#To create a certificate request file based on the private key, you need to enter some meta information of the certificate: mailbox, domain name, etc
openssl req -out ca.req -key ca.key -new -config ./ca_cert.conf
openssl req -out server.req -key server.key -new -config ./server_cert.conf
openssl req -out client.req -key client.key -new -config ./client_cert.conf

#Combine the private key with the request file to create a self signed certificate
openssl x509 -req -in ca.req -out ca.crt -sha1 -days 5000 -signkey ca.key
openssl x509 -req -in server.req -out server.crt -sha1 -CAcreateserial -days 5000 -CA ca.crt -CAkey ca.key
openssl x509 -req -in client.req -out client.crt -sha1 -CAcreateserial -days 5000 -CA ca.crt -CAkey ca.key

mv ca.crt ca.key ca/
mv server.crt server.key server/
mv client.crt client.key client/

rm *.conf
rm *.req
rm *.srl

Interpretation of some commands

openssl genrsa [-out filename] [-passout arg] [-des] [-des3] [-idea] [numbits]

Option Description:
-Out filename: save the generated private key to the filename file. If no output file is specified, it is standard output.
-Numbits: Specifies the length of the private key to be generated. The default is 1024. This must be the last argument on the command line.
-Des | - DES3 | - idea: Specifies the algorithm used to encrypt the private key file, so that the password will be entered every time the private key file is used. It is too troublesome, so it is rarely used.
-Passout args: the format of the password passed when encrypting the private key file. If this item is not specified when encrypting the private key file, you will be prompted to enter the password. The format of args that passed the password

openssl req -out ca.req -key ca.key -new -config ./ca_cert.conf
Main command options:
-New: generate certificate request file
-Key: specify the existing secret key file to generate a secret key request, which is only matched with the generate certificate request option - new.
-Out: Specifies the name of the generated certificate request or self signed certificate

openssl x509 -req -in ca.req -out ca.crt -sha1 -days 5000 -signkey ca.key
OpenSSL x509 command has the following functions, such as outputting certificate information, signing certificate request file, generating self signed certificate, converting certificate format, etc.
-In filename: specify the certificate input file. If the "- req" option is also specified, it means that the input file is a certificate request file, and then use "- signkey" to provide the private key used during self signing.
-Out filename: Specifies the output file
-Days: specifies how long the certificate is valid. The default is 30 days

4、 Install flash

You need to install the OpenSSL class library of Python. Use pip to install

pip install pyOpenSSL

5、 HTTPS one-way authentication handshake process

How to implement HTTPS using Python + flask
Python implementation

Server side:

from flask import Flask
app = Flask(__name__)

@app.route('/login')
def hello_world():
    return 'Hello World!'
 
if __name__ == '__main__':
    app.run(host="0.0.0.0", port=8091, ssl_context=('server.crt', 'server.key'))

client:

import urllib.request

import ssl

if __name__ == '__main__':
    CA_FILE = "ca.crt"
    context = ssl.SSLContext(ssl.PROTOCOL_TLS)
    context.check_hostname = False
    context.load_verify_locations(CA_FILE)
    context.verify_mode = ssl.CERT_REQUIRED
    try:
        request = urllib.request.Request('https://127.0.0.1:8091/login')
        res = urllib.request.urlopen(request, context=context)
        print(res.code)
        print(res.read().decode("utf-8"))
    except Exception as ex:
        print("Found Error in auth phase:%s" % str(ex))

6、 HTTPS two-way authentication handshake process

How to implement HTTPS using Python + flask

Python implementation

client:

from flask import Flask, request, Response
import json

app = Flask(__name__)
@app.route("/login")
def hello():
    return "Hello World!"
@app.route('/login1', methods=['POST'])
def login():
    username = request.form.get("username")
    password = request.form.get("password")
    login_config = {
        "name": "pwd1"
    }
    if username in login_config.keys():
        if password == login_config[username]:
            return Response(json.dumps(True), status=200, mimetype='application/json')

    return Response(json.dumps(False), status=200, mimetype='application/json')
if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8091, ssl_context=('server/server.crt', 'server/server.key'))

client:

import urllib.request

import ssl

if __name__ == '__main__':
    CA_FILE = "ca.crt"

    context = ssl.SSLContext(ssl.PROTOCOL_TLS)
    context.check_hostname = False
    context.load_verify_locations(CA_FILE)
    context.verify_mode = ssl.CERT_REQUIRED
    dict = {
        "username": "name",
        "password": "pwd1",
    }
    data = urllib.parse.urlencode(dict).encode('utf-8')
    try:
        request = urllib.request.Request('https://127.0.0.1:8091/login')
        res = urllib.request.urlopen(request, context=context)
        print(res.code)
        print(res.read().decode("utf-8"))
    except Exception as ex:
        print("Found Error in auth phase:%s" % str(ex))
    try:
        request = urllib.request.Request('https://127.0.0.1:8091/login1', data=data, method='POST')
        res = urllib.request.urlopen(request, context=context)
        print(res.code)
        print(res.read().decode("utf-8"))
    except Exception as ex:
        print("Found Error in auth phase:%s" % str(ex))

Reference link

OpenSSL command (1): detailed explanation of OpenSSL req command

Introduction to OpenSSL – instruction x509

OpenSSL command (3): detailed explanation of OpenSSL x509 command

OpenSSL command – pkcs12

Ten minutes to understand HTTP and HTTPS protocols?

HTTPS one-way authentication and two-way authentication

Implementation of SSL / TLS authentication in Python

Click focus to learn about Huawei cloud’s new technologies for the first time~