自簽SSL證書實現客戶端登錄認證
- 2020 年 4 月 4 日
- 筆記
0.介紹
自己開發的使用了SSL協議的軟體,通常沒必要從證書籤發機構那裡來獲取證書,自簽證書成了必要的選擇。自簽證書還可以用來實現客戶端登錄認證。
1.創建CA
創建CA的私鑰 openssl genrsa -des3 -out rootCA.key 4096 創建CA的自簽證書 openssl req -x509 -new -nodes -sha256 -days 3650 -key rootCA.key -out rootCA.crt
2.簽發證書
生成證書的私鑰 openssl genrsa -out server.key 4096 生成待簽名的文件 openssl req -new -key server.key -out server.csr 使用CA進行簽名 openssl x509 -req -CA rootCA.crt -CAKey rootCA.key -CAcreateserial -days 365 -sha256 -in server.csr -out server.crt
這樣就獲取了經CA簽發的私鑰server.key和證書server.crt
3.客戶端的登錄認證
使用相同的CA來簽發伺服器證書和客戶端證書,伺服器就可以根據CA證書來鑒定客戶端的是否具有登錄許可權。
即:凡是經過CA簽發的證書,都能登錄成功;否則失敗 。
4.Python程式碼示例,演示如何驗證客戶端的證書
服務端程式碼:
import socket from socket import AF_INET, SOCK_STREAM, SO_REUSEADDR, SOL_SOCKET, SHUT_RDWR import ssl listen_addr = '127.0.0.1' listen_port = 8082 server_cert = 'server.crt' server_key = 'server.key' ca_cert = 'rootCA.crt' context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH, cafile=ca_cert) context.verify_mode = ssl.CERT_REQUIRED context.load_cert_chain(certfile=server_cert, keyfile=server_key) # context.load_verify_locations(cafile=ca_cert) bindsocket = socket.socket() bindsocket.bind((listen_addr, listen_port)) bindsocket.listen(5) while True: print("Waiting for client") newsocket, fromaddr = bindsocket.accept() print("Client connected: {}:{}".format(fromaddr[0], fromaddr[1])) conn = context.wrap_socket(newsocket, server_side=True) print("SSL established. Peer: {}".format(conn.getpeercert())) buf = b'' # Buffer to hold received client data try: while True: data = conn.recv(4096) if data: # Client sent us data. Append to buffer buf += data else: # No more data from client. Show buffer and close connection. print("Received:", buf) break finally: print("Closing connection") conn.shutdown(socket.SHUT_RDWR) conn.close()
客戶端程式碼
import socket import ssl host_addr = '127.0.0.1' host_port = 8082 server_sni_hostname = 'example.com' ca_cert = 'rootCA.crt' client_cert = 'client.crt' client_key = 'client.key' context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cafile=ca_cert) context.check_hostname = False context.load_cert_chain(certfile=client_cert, keyfile=client_key) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) conn = context.wrap_socket(s, server_side=False, server_hostname=server_sni_hostname) conn.connect((host_addr, host_port)) print("SSL established. Peer: {}".format(conn.getpeercert())) print("Sending: 'Hello, world!") conn.send(b"Hello, world!") print("Closing connection") conn.close()
參考
- 創建證書https://gist.github.com/fntlnz/cf14feb5a46b2eda428e 09
- Python的SSL程式碼https://www.electricmonk.nl/log/2018/06/02/ssl-tls-client-certificate-verification-with-python-v3-4-sslcontext/