摘要:通常http中存在請求信息明文傳輸,容易被竊聽截取;數據的完整性未校驗,容易被篡改;沒有驗證對方身份,存在冒充危險。面對這些問題,怎麼破?
本文分享自華爲雲社區《https如何使用python+flask來實現》,原文做者:SNHer 。python
通常http中存在以下問題:請求信息明文傳輸,容易被竊聽截取;數據的完整性未校驗,容易被篡改;沒有驗證對方身份,存在冒充危險。算法
一、使用HTTPS可認證用戶和服務器,確保數據發送到正確的客戶機和服務器。shell
二、HTTPS是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,要比http協議安全,可防止數據在傳輸過程當中不被竊取、改變,確保數據的完整性。json
三、HTTPS是現行架構下最安全的解決方案,雖然不是絕對安全,但它大幅增長了中間人攻擊的成本。flask
CA:證書受權中心( certificate authority)相似於國家出入境管理處同樣,給別人頒發護照;也相似於國家工商管理局同樣,給公司企業頒發營業執照。它有兩大主要性質:segmentfault
CA 的證書 ca.crt 和 SSL Server的證書 server.crt 是什麼關係呢?安全
#!/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
一些命令的解釋bash
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天
須要安裝python 的 openssl 的類庫,使用pip 安裝服務器
pip install pyOpenSSL
網絡
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))
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認證的實現