完成HTTPS请求的主体
- 首先是服务端(server),要生成证书请求(csr),提交给CA(Certificate Authority),即证书授权中心,获得一张证书。这个证书里面包括了服务端的公钥,CA使用其私钥对服务端的公钥进行加密后得到的签名。
- 然后是证书授权中心(CA),负责接收证书请求(包含请求主体的主体信息、公钥和签名算法),使用自己的私钥对请求中的信息进行加密签名。此前CA需要先给自己颁发一个根证书,下面还要用来给其他主体的证书请求颁发证书。
- 最后是客户端(client),在访问HTTPS网站时,收到了服务端发来的证书,此时客户端要向CA查询这张证书是否合法,从而决定是否与此网站通信。这是就要用CA的公钥来解密这张证书中的数字签名,看是否与证书的明文部分一致。这意味着CA的根证书需要保存在浏览器中,各大浏览器开发商一般都会把根证书内置在浏览器中
openssl基础命令
openssl genrsa命令:
openssl req 命令:
openssl x509 命令:
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()