如果你想在分布式系统中实现一个简单的客户端链接认证功能,又不像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)