https如何使用python+flask來實現

華為雲開發者社群發表於2021-04-22
摘要:一般http中存在請求資訊明文傳輸,容易被竊聽擷取;資料的完整性未校驗,容易被篡改;沒有驗證對方身份,存在冒充危險。面對這些問題,怎麼破?

一、為什麼要用https

一般http中存在如下問題:請求資訊明文傳輸,容易被竊聽擷取;資料的完整性未校驗,容易被篡改;沒有驗證對方身份,存在冒充危險。

HTTPS又有哪些優勢?

1、使用HTTPS可認證使用者和伺服器,確保資料傳送到正確的客戶機和伺服器。

2、HTTPS是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網路協議,要比http協議安全,可防止資料在傳輸過程中不被竊取、改變,確保資料的完整性。

3、HTTPS是現行架構下最安全的解決方案,雖然不是絕對安全,但它大幅增加了中間人攻擊的成本。

二、https中的證照是什麼

https如何使用python+flask來實現

CA:證照授權中心( certificate authority)類似於國家出入境管理處一樣,給別人頒發護照;也類似於國家工商管理局一樣,給公司企業頒發營業執照。它有兩大主要性質:

  • CA本身是受信任的,國際認可的;
  • 給他受信任的申請物件頒發證照。 和辦理護照一樣,要確定你的合法身份,你不能是犯罪分子或造反派。當然,你需要被收保護費,同時,CA可以隨時吊銷你的證照。

CA 的證照 ca.crt 和 SSL Server的證照 server.crt 是什麼關係呢?

  • SSL Server 自己生成一個 私鑰/公鑰對,server.key/server.pub 。server.pub 生成一個請求檔案 server.req。 請求檔案中包含有 server 的一些資訊,如域名/申請者/公鑰等。
  • server 將請求檔案 server.req 遞交給 CA,CA驗明正身後,將用 ca.key和請求檔案加密生成 server.crt由於 ca.key 和 ca.crt 是一對, 於是 ca.crt 可以解密 server.crt。
  • 在實際應用中:如果 SSL Client 想要校驗 SSL server.那麼 SSL server 必須要將他的證照 server.crt 傳給 client.然後 client 用 ca.crt 去校驗 server.crt 的合法性。如果是一個釣魚網站,那麼CA是不會給他頒發合法server.crt證照的,這樣client 用ca.crt去校驗,就會失敗。

三、生成證照與金鑰

shell指令碼

#!/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

# 生成私鑰
openssl genrsa -out ca.key 1024
openssl genrsa -out server.key 1024
openssl genrsa -out client.key 1024

# 根據私鑰建立證照請求檔案,需要輸入一些證照的元資訊:郵箱、域名等
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

# 結合私鑰和請求檔案,建立自簽署證照
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

一些命令的解釋

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

選項說明:
-out filename:將生成的私鑰儲存至filename檔案,若未指定輸出檔案,則為標準輸出。
-numbits:指定要生成的私鑰的長度,預設為1024。該項必須為命令列的最後一項引數。
-des|-des3|-idea:指定加密私鑰檔案用的演算法,這樣每次使用私鑰檔案都將輸入密碼,太麻煩所以很少使用。
-passout args:加密私鑰檔案時,傳遞密碼的格式,如果要加密私鑰檔案時單未指定該項,則提示輸入密碼。傳遞密碼的args的格式

openssl req -out ca.req -key ca.key -new -config ./ca_cert.conf
主要命令選項:
-new :說明生成證照請求檔案
-key :指定已有的祕鑰檔案生成祕鑰請求,只與生成證照請求選項-new 配合。
-out :指定生成的證照請求或者自簽名證照名稱

openssl x509 -req -in ca.req -out ca.crt -sha1 -days 5000 -signkey ca.key
openssl x509命令具以下的一些功能,例如輸出證照資訊,簽署證照請求檔案、生成自簽名證照、轉換證照格式等。
-in filename:指定證照輸入檔案,若同時指定了"-req"選項,則表示輸入檔案為證照請求檔案,再使用"-signkey"提供自簽署時使用的私鑰。
-out filename:指定輸出檔案
-days: 指定證照的有效時間長短。預設為30天

四、安裝flask

需要安裝python 的 openssl 的類庫,使用pip 安裝

pip install pyOpenSSL

五、https單向認證握手流程

https如何使用python+flask來實現

python實現

server端:

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

客戶端:

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

六、https雙向認證握手流程

https如何使用python+flask來實現

python實現

客戶端:

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

客戶端:

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

參考連結

openssl 命令(1): openssl req 命令詳解

openssl簡介-指令x509

openssl 命令(3): openssl x509命令詳解

OpenSSL命令—pkcs12

十分鐘搞懂HTTP和HTTPS協議?

Https單向認證和雙向認證

python關於SSL/TLS認證的實現

 本文分享自華為雲社群《https如何使用python+flask來實現》,原文作者:SNHer 。

點選關注,第一時間瞭解華為雲新鮮技術~

相關文章