一、os.urandom(n)
获取一种bytes类型的随机生成的n个字节字符串的方法,每次生成的值都不相同。
二、hmac
hmac模块实现了标准的Hmac算法,首先需要准备待计算的原始消息key,和随机生成的msg,哈希算法,采用MD5,使用hmac的代码如下:
import hmac key = b"Hello World" msg = b"secret" h = hmac.new(key, msg, digestmod='MD5') print(h.hexdigest()) # 8a315e3168dcd347b8bb3e2517da7b4d
注:传入的key和msg必须为bytes类型。
三、验证客户端的链接合法性
如果服务端想限制客户端访问,就必须对客户端进行认证,认证通过方可访问。否则客户端只需知道服务端ip和端口号就能对其进行访问。
如果你想在分布式系统中实现一个简单的客户端链接认证功能,又不像SSL那么复杂,那么利用hmac + 加盐的方式来实现
服务端:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import socket import hmac import os secret_key = b"Jedan has a big key!" # 盐 def conn_auth(conn): """ 认证客户端链接 :param conn:管道 :return:True/False """ print("开始验证新链接的合法") msg = os.urandom(32) # 生成一个32字节的bytes类型随机字符串 conn.sendall(msg) # 发送随机字符串 h = hmac.new(secret_key, msg) digest = h.digest() # 得到密文 response = conn.recv(len(digest)) # 接收客户端密文 # hmac.compare_digest(密文,密文),比较客户端密文与服务端密文是否相同,相同返回True,不同返回False return hmac.compare_digest(response, digest) def data_handler(conn, bufsize=1024): """ 判断链接是否合法 :param conn: 管道 :param bufsize: 接收数据长度 :return: None """ if not conn_auth(conn): print("该链接不合法") conn.close() return print("链接合法") while 1: data = conn.recv(bufsize) if not data: break conn.sendall(data.upper()) def server_handler(ip_port, bufsize, backlog=5): """ 只处理链接 :param ip_port:地址(ip+port) :param bufsize:接收数据长度 :param backlog:监听数 :return:data_handler(conn, bufsize) """ tcp_socket_server = socket.socket() # 创建socket对象 tcp_socket_server.bind(ip_port) # 绑定端口 tcp_socket_server.listen(backlog) # 监听 while 1: conn, addr = tcp_socket_server.accept() print("新连接[%s:%s]" % (addr[0], addr[1])) data_handler(conn, bufsize) if __name__ == '__main__': ip_port = ("127.0.0.1", 8001) bufsize = 1024 server_handler(ip_port, bufsize)
客户端:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import socket import hmac secret_key = b"Jedan has a big key!" # 盐 def conn_auth(conn): """ 验证客户端到服务器端的链接 :param conn: :return: """ msg = conn.recv(32) h = hmac.new(secret_key, msg) digest = h.digest() conn.sendall(digest) # 发送客户端密文 def client_handler(ip_port, bufsize=1024): """ 发送密文验证,验证成功实现通信 :param ip_port:地址 :param bufsize:数据接收长度 :return:None """ tcp_socket_client = socket.socket() tcp_socket_client.connect(ip_port) conn_auth(tcp_socket_client) while 1: data = input(">>>(q退出)").strip() if not data: continue if data.upper() == "Q": break tcp_socket_client.sendall(data.encode("utf-8")) response = tcp_socket_client.recv(bufsize) print(response.decode("utf-8")) tcp_socket_client.close() if __name__ == '__main__': ip_port = ("127.0.0.1", 8001) bufsize = 1024 client_handler(ip_port, bufsize)