完成HTTPS請求的主體
- 首先是服務端(server),要生成證書請求(csr),提交給CA(Certificate Authority),即證書授權中心,獲得一張證書。這個證書裏面包括了服務端的公鑰,CA使用其私鑰對服務端的公鑰進行加密後得到的簽名。
- 然後是證書授權中心(CA),負責接收證書請求(包含請求主體的主體信息、公鑰和簽名算法),使用自己的私鑰對請求中的信息進行加密簽名。此前CA需要先給自己頒發一個根證書,下面還要用來給其他主體的證書請求頒發證書。
- 最後是客戶端(client),在訪問HTTPS網站時,收到了服務端發來的證書,此時客戶端要向CA查詢這張證書是否合法,從而決定是否與此網站通信。這是就要用CA的公鑰來解密這張證書中的數字簽名,看是否與證書的明文部分一致。這意味着CA的根證書需要保存在瀏覽器中,各大瀏覽器開發商一般都會把根證書內置在瀏覽器中
openssl基礎命令
openssl genrsa命令:https://blog.csdn.net/as3luyuan123/article/details/14498397?utm_source=blogxgwz3
openssl req 命令:https://blog.csdn.net/lsyyff23/article/details/79445370
openssl x509 命令:https://blog.csdn.net/u010846177/article/details/54356897
openssl模擬該過程
- openssl安裝
$ sudo apt-get install openssl
$ sudo apt-get install libssl-dev
- 生成CA根證書
- 創建私鑰:
$ openssl genrsa -out ca-key.pem 1024
- 創建 csr 證書請求
$ openssl req -new -key ca-key.pem -out ca-req.csr -subj "/C=CN/ST=BJ/L=BJ/O=BD/OU=BD/CN=CS"
- 生成根證書(用自己(CA)的私鑰來簽名):
$ openssl x509 -req -in ca-req.csr -out ca-cert.pem -signkey ca-key.pem -days 3650
- 創建私鑰:
- 生成服務端證書
- 創建服務端私鑰:
$ openssl genrsa -out server-key.pem 1024
- 創建csr證書請求:
$ openssl req -new -out server-req.csr -key server-key.pem -subj "/C=CN/ST=SH/L=SH/O=TM/OU=TM/CN=CS"
- 生成證書(用根證書和CA的私鑰來簽名):
$ openssl x509 -req -in server-req.csr -out server-cert.pem -signkey server-key.pem -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -days 3650
- 創建服務端私鑰:
- 確認證書
openssl verify -CAfile ca-cert.pem server-cert.pem
基於Python的簡單HTTPS服務
調用Python的http,ssl庫,實現簡單的HTTPS服務,這裏提供服務端的證書與私鑰即可。這裏的CA證書是我們本地生成的,瀏覽器不會信任,訪問時點擊允許訪問不安全的網站即可。若要避免這一問題,需要在網上購買權威CA的服務,生成被瀏覽器信任的證書。
下面的小程序實現了GET請求的處理,將調用其他Python程序來進一步處理請求。
#-*-coding:utf-8-*-
from http import server
from http.server import BaseHTTPRequestHandler
import socket
import ssl
import sys
import subprocess
import os
class RequestHandler(BaseHTTPRequestHandler):
def send_content(self, page, status = 200):
self.send_response(status)
self.send_header("Content-type", "text/html")
self.send_header("Content-Length", str(len(page)))
self.end_headers()
# print(type(page))
if type(page) == type('a'):
self.wfile.write(bytes(page, encoding = 'utf-8'))
elif type(page) == type(b'1'):
self.wfile.write(page)
print("response: ",page)
def runpy(self, path, query):
try:
res = subprocess.check_output("python %s %s"%(path, query),
stderr = subprocess.STDOUT,
shell = True)
self.send_content(res)
except subprocess.CalledProcessError as exc:
res = "returncode: %r" % exc.returncode
res += "cmd: %s" % exc.cmd
res += "output: %s" % exc.output
self.send_content(res)
def do_GET(self):
print("self.path",self.path)
if "?" in self.path:
path, query = self.path.split('?')
self.full_path = os.getcwd() + path
if (os.path.isfile(self.full_path) and self.full_path.endswith('.py')):
print("runing %s"%path.lstrip('/'))
self.runpy(path.lstrip('/'), query)
else:
print("%s not exist"%path)
self.send_content("%s not exist"%path)
else:
self.send_content("<h1 align='center'>Hello, World</h1>")
port = 443
try:
httpd = server.HTTPServer(("0.0.0.0", port),RequestHandler)
print("Listening on 0.0.0.0:443")
except:
port = 8443
httpd = server.HTTPServer(("0.0.0.0", port),RequestHandler)
print("Listening on 0.0.0.0:8443")
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.load_cert_chain("server-cert.pem","server-key.pem") #自己添加
httpd.socket = context.wrap_socket(httpd.socket, server_side = True)
try:
print("HTTTPS Server listening on 0.0.0.0:%d"%port)
httpd.serve_forever()
except KeyboardInterrupt:
print("User quit.")
exit()