Python之路(第三十四篇) 網路程式設計:驗證客戶端合法性
阿新 • • 發佈:2018-11-27
如果你想在分散式系統中實現一個簡單的客戶端連結認證功能,又不像SSL那麼複雜,那麼利用hmac+加鹽的方式來實現。
客戶端驗證的總的思路是將服務端隨機產生的指定位數的位元組傳送到客戶端,兩邊同時用hmac進行加密,然後對生成的密文進行比較,相同就是合法的客戶端,不相同就是不合法的端戶端。
服務端
from socket import *
import hmac, os
secret_key = b"nick" # 是指一個固定字串的key
def conn_auth(conn): # 定義函式認證客戶端連線
print('開始驗證新連結的合法性') # 列印提示
msg = os.urandom(32) # 隨機生成一個32位的數
conn.sendall(msg) # 連線傳送這個隨機的數
h = hmac.new(secret_key, msg) # 傳入要生成hmac摘要值的資訊
digest = h.digest() # 生成一個hmac摘要
respone = conn.recv(len(digest)) # 接收回應,連線接收一個伺服器端摘要的長度的資訊
return hmac.compare_digest(respone, digest) # 比較客戶端和服務端計算的摘要結果,一樣則是True,不一樣則是False
def data_handler(conn, bufsize=1024): # 資料處理機函式(傳入兩個引數conn,和設定的預設大小)
if not conn_auth(conn): # 如果沒有連結
print('該連結不合法,關閉') # 列印該連結不合法,關閉
conn.close() # 關閉連結
return
print('連結合法,開始通訊') # 連結合法,開始通訊
while True: # 迴圈為真
data = conn.recv(bufsize) # 接收資料
if not data: break # 如果沒有資料則打斷
conn.sendall(data.upper()) # 連結傳送資料
def server_handler(ip_port, bufsize, backlog=5): # 伺服器處理機ip和埠,設定大小
'''
只處理連結
:param ip_port:
:return:
'''
tcp_socket_server = socket(AF_INET, SOCK_STREAM) # 例項化一個tcp的套接字
tcp_socket_server.bind(ip_port) # 繫結ip埠
tcp_socket_server.listen(backlog) # 監聽
while True: # 迴圈為真
conn, addr = tcp_socket_server.accept() # 接收連結和地址
print('新連線[%s:%s]' % (addr[0], addr[1])) # 列印新連線ip和埠
data_handler(conn, bufsize) # 呼叫資料處理機函式
if __name__ == '__main__':
ip_port = ('127.0.0.1', 9999)
bufsize = 1024
server_handler(ip_port, bufsize)
客戶端
from socket import * import hmac, os secret_key = b'nick' # 設定一個字串key def conn_auth(conn): # 定義一個客戶驗證到伺服器端的連結 ''' 驗證客戶端到伺服器的連結 :param conn: :return: ''' msg = conn.recv(32) # 接受一個32位的資訊 h = hmac.new(secret_key, msg) digest = h.digest() # 得到一個摘要值 conn.sendall(digest) # 傳送這個摘要 def client_handler(ip_port, bufsize=1024): tcp_socket_client = socket(AF_INET, SOCK_STREAM) # 建立一個tcp套接字的物件 tcp_socket_client.connect(ip_port) conn_auth(tcp_socket_client) # 執行驗證 while True: data = input('>>: ').strip() # 輸入內容 if not data: continue # 如果沒有內容則跳過 if data == 'quit': break tcp_socket_client.sendall(data.encode('utf-8')) # 傳送資料 respone = tcp_socket_client.recv(bufsize) # 接收資料 print(respone.decode('utf-8')) # 列印接收的資料 tcp_socket_client.close() # 關閉這個套接字 if __name__ == '__main__': ip_port = ('127.0.0.1', 9999) bufsize = 1024 client_handler(ip_port, bufsize)