Hmac模塊 其實這個模塊類似hashlib模塊,它能將一些重要的信息通過演算法加密成密文,讓信息更具有安全性。 關於hmac加密演算法的瞭解:它的全名是哈希運算消息認證碼(Hash-based Message Authentication Code),HMAC利用hash演算法,以一個消息M和一個秘鑰K ...
Hmac模塊
其實這個模塊類似hashlib模塊,它能將一些重要的信息通過演算法加密成密文,讓信息更具有安全性。
關於hmac加密演算法的瞭解:它的全名是哈希運算消息認證碼(Hash-based Message Authentication Code),HMAC利用hash演算法,以一個消息M和一個秘鑰K作為輸入,生成一個定長的消息摘要作為輸出。HMAC演算法利用已有的hash函數,關鍵問題是如何使用秘鑰。
使用
import hmac #這個模塊和hashlib機制很相似 h = hmac.new(b'key',b'msg') #需要一個秘鑰(bytes類型)和你想進行加密的bytes類型數據,前面為隨機的key後面為一個消息 print(h.digest()) #結果拿到一個密文 #b'\x18\xe3T\x8cY\xad@\xdd\x03\x90{z\xee\xe7\x1dg'
檢驗客戶端合法性
如何確定這個客戶端是該伺服器的合法客戶端呢?如果兩邊實現都講好了他們的秘鑰就可以利用hmac.compare_digest()方法去比較他們最後產生的密文到底是不是相同的,如果是那就是合法的就進行相應的操作,若不合法就直接關閉。
這裡介紹一個新的os模塊方法urandom(32)
import os print(os.urandom(32)) #隨機生成32位的位元組 #b'\xe2\x84:\x93\x82Q9\xff\x9e\x7f\x8a\x97)[\xedn\r\xa8\xf0v\x8b\xc0g\xbd\xe7\xeb\x0e\xa4\xf0\x80\x0c\x16'
利用這種'加鹽'的方法我們就能讓我們產生的秘鑰具有不確定性,更加安全
檢驗合法的結果:
Sever:
import socket import hmac from os import urandom secret_key = b'egg' #秘鑰 sk = socket.socket() sk.bind(('127.0.0.1',8090)) sk.listen() def check_conn(conn): constant = urandom(32) conn.send(constant) h = hmac.new(secret_key,constant) #拿到一個密文對象 sever_digest = h.digest() client_digest = conn.recv(1024) return hmac.compare_digest(sever_digest,client_digest) conn,addr = sk.accept() res = check_conn(conn) if res: print('合法的客戶端!') #合法的客戶端! #進行一系列操作 #conn.close() pass else: print('不合法的客戶端!') conn.close() sk.close()
Client:
import socket import hmac secret_key = b'egg' sk = socket.socket() sk.connect(('127.0.0.1',8090)) msg = sk.recv(1024) h = hmac.new(secret_key,msg) client_digest = h.digest() sk.send(client_digest) sk.close()
那如果這個客戶端它並不知道服務端的秘鑰或者不知道服務端用的是HMAC進行的加密,那麼它的結果很有可能是錯誤,給我們返回錯誤的客戶端!
Socketsever模塊
socketsever模塊它能夠實現多個客戶端之間的交互
基本實現
Sever:
import socketserver class Mysever(socketserver.BaseRequestHandler): #一般情況下帶Base都是作為父類,Request即請求,Handler就是處理 def handle(self): print(self.request.recv(1024).decode('utf-8')) #self.request相當於一個conn if __name__ == '__main__': sever = socketserver.ThreadingTCPServer(('127.0.0.1',8080),Mysever) #Thread線程 #在一個程式里正常情況下只會有一個線程 #一個線程就是調度CPU的最小單位 #引入線程的概念去實現併發的效果 sever.serve_forever() #表示我永遠啟用一個服務
Client:
import socket sk = socket.socket() sk.connect(('127.0.0.1',8080)) sk.send('hi'.encode('utf-8')) sk.close()
Output:
hi
有socketsever的原因就是我想同時處理多個客戶端找我下載的請求,那socketsever只是在底層的基礎上做了一層封裝,幫我們實現了併發效果,所以沒有'clientsever'這個概念,客戶端只需要正常啟用就好
實現多個客戶端交互
Sever:
import socketserver class Mysever(socketserver.BaseRequestHandler): def handle(self): while True: msg = self.request.recv(1024).decode('utf-8') print(msg) info = input('<<<').encode('utf-8') self.request.send('Sever:'.encode('utf-8') + info) if __name__ == '__main__': sever = socketserver.ThreadingTCPServer(('127.0.0.1',8080),Mysever) sever.serve_forever()
Client1:
import socket sk = socket.socket() sk.connect(('127.0.0.1',8080)) while True: msg = input('<<<').encode('utf-8') sk.send('Client1:'.encode('utf-8') + msg) print(sk.recv(1024).decode('utf-8')) sk.close()
Client2:
import socket sk = socket.socket() sk.connect(('127.0.0.1',8080)) while True: msg = input('<<<').encode('utf-8') sk.send('Client2:'.encode('utf-8') + msg) print(sk.recv(1024).decode('utf-8')) sk.close()
Output: