自簽SSL證書實現客戶端登錄認證

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

  

參考