铁乐学Python_Day35_Socket模块3和hmac模块
验证客户端链接的合法性
如果你想在分布式系统中实现一个简单的客户端链接认证功能,又不像SSL那么复杂,
那么可以利用hmac+加盐的方式来实现。
例1:简单的服务端如下
#!/usr/bin/env python
# _*_ coding: utf-8 _*_
import os
import socket
import hmac
secret_key = '老衲洗头用飘柔'.encode('utf-8')
server = socket.socket()
server.bind(('127.0.0.1', 9527))
server.listen()
while True:
try:
conn, addr = server.accept()
random_bytes = os.urandom(32)
conn.send(random_bytes)
hmac_obj = hmac.new(key=secret_key, msg=random_bytes)
ret = hmac_obj.hexdigest()
print(hmac_obj.hexdigest())
msg = conn.recv(1024).decode('utf-8')
if msg == ret:
print('是合法的客户端')
else:
print('不是合法的客户端')
conn.close()
finally:
server.close()
break
客户端如下:
#!/usr/bin/env python
# _*_ coding: utf-8 _*_
import socket
import hmac
secret_key = '老衲洗头用飘柔'.encode('utf-8')
client = socket.socket()
client.connect(('127.0.0.1', 9527))
urandom = client.recv(1024)
hmac_obj = hmac.new(key=secret_key, msg=urandom)
client.send(hmac_obj.hexdigest().encode('utf-8'))
print('--------')
client.close()
效果如下:
33e40f5f66b2e9b2867a7862d02fba9d
是合法的客户端。
例2:TCP时间戳服务器验证
#!/usr/bin/env python
# _*_ coding: utf-8 _*_
import os
import hmac
from socket import *
from time import ctime
'''
socket tcp时间戳服务端,利用hmac模块加盐验证客户端连接的合法性
'''
# 加盐
secret_key = '芝麻开门'.encode('utf-8')
def conn_auth(conn):
'''
认证客户端链接
:param conn: 客户端链接
:return: True or False
'''
print('开始验证新链接的合法性')
# os模块生成随机32位字符串,用于发送给客户端验证
ustr = os.urandom(32)
conn.sendall(ustr)
# 生成密钥 hmac加盐+32位随机字符串
cipher = hmac.new(secret_key, ustr).digest()
# 接收客户端发送过来的密钥,长度和这边生成的应当一致
result = conn.recv(len(cipher))
# compare 两相比较,一致返回true,否则为false
return hmac.compare_digest(result, cipher)
def data_handler(conn,bufsize=1024):
# 如果验证不通过
if not conn_auth(conn):
print('链接非法,关闭')
conn.close()
return
print('链接已通过验证,开始通信')
while True:
data = conn.recv(bufsize)
if not data:break
data = '[%s] %s' % (ctime(), data.decode('utf-8'))
conn.sendall(data.encode('utf-8'))
conn.close()
def server_handler(host,port,bufsize=1024,num=5):
'''
socket tcp服务端设置
:param host: 主机名或ip地址
:param port: 端口号
:param bufsize: 缓冲区大小,默认1024
:param num: 侦听最大客户端,默认5位
:return:
'''
tcpss = socket(AF_INET, SOCK_STREAM)
tcpss.bind((host,port))
tcpss.listen(num)
while True:
conn, addr = tcpss.accept()
print('新连接[%s:%s]' % (addr[0], addr[1]))
data_handler(conn,bufsize)
if __name__ == '__main__':
host = 'localhost'
port = 9527
server_handler(host, port)
TCP时间戳客户端:
#!/usr/bin/env python
# _*_ coding: utf-8 _*_
'''
socket tcp时间戳客户端,利用hmac模块加盐验证客户端连接的合法性
'''
import os
import hmac
from socket import *
secret_key = '芝麻开门'.encode('utf-8')
def conn_auth(conn):
'''
验证客户端到服务器的链接
:param conn: 链接
:return: True or False
'''
# 客户端接收32位随机字节
ustr = conn.recv(32)
# hmac加盐加密文得出最终密钥并发送回服务端
cipher = hmac.new(secret_key, ustr).digest()
conn.sendall(cipher)
def client_handler(host,port,bufsize=1024):
tcpsc = socket(AF_INET, SOCK_STREAM)
tcpsc.connect((host, port))
conn_auth(tcpsc)
while True:
data = input('>>>').strip()
if not data:continue
if data == 'quit':break
tcpsc.sendall(data.encode('utf-8'))
result = tcpsc.recv(bufsize)
print(result.decode('utf-8'))
tcpsc.close()
if __name__ == '__main__':
host = 'localhost'
port = 9527
bufsize = 1024
client_handler(host, port, bufsize)
效果:
服务端:
D:\PortableSoft\Python35\python.exe E:/Python/重要的代码/socket_hmac验证合法连接/tcpss.py
新连接[127.0.0.1:57600]
开始验证新链接的合法性
链接已通过验证,开始通信
客户端:
D:\PortableSoft\Python35\python.exe E:/Python/重要的代码/socket_hmac验证合法连接/tcpsc.py
>>>time
[Thu May 10 22:00:19 2018] time
>>>也许猪的身体不优美,长鼻短尾,但是别人不可天空里高飞
[Thu May 10 22:01:10 2018] 也许猪的身体不优美,长鼻短尾,但是别人不可天空里高飞
>>>
socketserver
SocketServer是标准库中的一个高级模块(python3.x中重命名为socketserver),
它的目标是简化很多样板代码,它们是创建网络客户端和服务器所必需的代码。
这个模块中有为你创建的各种各样的类,如下表所示:
除了为你隐藏了实现细节之外,另一个不同之处是,我们现在使用类来编写应用程序,
以面向对象的方式处理事务有助于组织数据,以及逻辑性地将功能放在正确的地方。
你还会注意到,应用程序现在是事件驱动的,这意味着只有在系统中的事件发生时,它们才会工作。
事件包括消息的发送和接收。
事实上,你会看到类定义只包括一个用来接收客户端消息的事件处理程序。
所有其它的功能都来自使用的SocketServer类。
在原始服务器循环中,我们阻塞等待请求,当接收到请求时就对其提供服务,然后继续等待。
在此处的服务器循环中,并非在服务器中创建代码,而是定义一个处理程序,
这样当服务器接收到一个传入的请求时,服务器就可以调用你的函数。
创建SocketServer TCP服务器
#!/usr/bin/env python
# _*_ coding: utf-8 _*_
'''
通过使用socketserver类、TCPServer和StreamRequesthandler,该脚本创建了一个时间戳TCP服务器。
'''
from socketserver import (TCPServer as TCP, StreamRequestHandler as SRH)
from time import ctime
HOST = '127.0.0.1'
PORT = 9527
ADDR = (HOST, PORT)
class MyRequestHandler(SRH):
# 重写handle方法,该方法在基类Request中默认情况下没有任何行为(pass)
# 但当接收到一个客户端的消息时,它就会调用handle()方法,因此得重写进行处理。
def handle(self):
print('...connected from:', self.client_address)
# StreamRequsetHandler将输入和输出套接字看作类似文件的对象
# 因此可以使用readline()获取客户端消息,当然此时客户端要约定消息附带\n换行符
data = '[%s] %s' % (ctime(), self.rfile.readline().decode('utf-8'))
# 同理,视作文件对象,使用write()将字符串发送回客户端
self.wfile.write(data.encode('utf-8'))
tcpServ = TCP(ADDR, MyRequestHandler)
print('waiting for connection...')
# 注:是serve,而不是server;forever为无限循环地等待并服务于客户端请求。
tcpServ.serve_forever()
创建SocketServer TCP客户端
#!/usr/bin/env python
# _*_ coding: utf-8 _*_
from socket import *
HOST = 'localhost'
PORT = 9527
BUFSIZ = 1024
ADDR = (HOST, PORT)
while True:
'''
和之前socker普通的tcp客户端从输入才开始循环不同,
sockerserver请求处理程序的默认行为是接受连接、获取请求,然后关闭连接。
由于这个原因,我们不能在应用程序整个执行过程中都保持连接,因此每次向服务器发送消息时,
都需要创建一个新的套接字。
'''
tcpCliSock = socket(AF_INET, SOCK_STREAM)
tcpCliSock.connect(ADDR)
data = input('>>>')
if not data:
break
'''
这里使用的处理程序对待套接字通信就像是文件一样,所以必須发送行终止符(回车和换行符)。
而服务器只是保留并重用这里发送的终止符。
'''
data = '%s\r\n' % data
tcpCliSock.send(data.encode('utf-8'))
resu = tcpCliSock.recv(BUFSIZ)
if not resu:
break
# 加strip()处理掉换行符
print(resu.decode('utf-8').strip())
tcpCliSock.close()
运行服务端和客户端后效果如下:
client端:
>>>百变星君
[Wed May 9 20:44:11 2018] 百变星君
>>>大圣娶亲
[Wed May 9 20:44:22 2018] 大圣娶亲
>>>
server端:
----------------------------------------
Exception happened during processing of request from ('127.0.0.1', 53286)
----------------------------------------
...connected from: ('127.0.0.1', 53397)
...connected from: ('127.0.0.1', 53398)
...connected from: ('127.0.0.1', 53399)
另一种不看成文件操作的支持并发连接的TCP时间戳服务器和客户端如下:
socketserver TCP时间戳服务器
#!/usr/bin/env python
# _*_ coding: utf-8 _*_
import socketserver
from time import ctime
# 并发编程
class MyServer(socketserver.BaseRequestHandler):
def handle(self):
print('...连接来自:', self.client_address)
msg = self.request.recv(1024)
msg = '[%s] %s' % (ctime(), msg.decode('utf-8'))
print(msg)
self.request.send(msg.encode('utf-8'))
if __name__ == '__main__':
# 支持重用端口和Ip
socketserver.TCPServer.allow_reuse_address = True
# ThreadingTCPServer 支持线程功能
server = socketserver.ThreadingTCPServer(('127.0.0.1', 9527), MyServer)
print('等待连接...')
server.serve_forever()
socketserver TCP时间戳客户端
#!/usr/bin/env python
# _*_ coding: utf-8 _*_
import socket
while True:
client = socket.socket()
client.connect(('127.0.0.1', 9527))
data = input('>>>')
if not data:
break
client.send(data.encode('utf-8'))
resu = client.recv(1024)
if not resu:
break
print(resu.decode('utf-8'))
client.close()
运行效果如下:
第一个client端:
>>>哆啦A梦
[Wed May 9 20:59:14 2018] 哆啦A梦
>>>蜡笔小新
[Wed May 9 20:59:27 2018] 蜡笔小新
>>>超人迪加
[Wed May 9 21:00:13 2018] 超人迪加
>>>
第二个client端:
>>>银河唯一的秘密
[Wed May 9 20:59:50 2018] 银河唯一的秘密
>>>护卫人类,挽救地球,看守这宇宙
[Wed May 9 21:00:35 2018] 护卫人类,挽救地球,看守这宇宙
>>>
socketserver服务端:
等待连接...
...连接来自: ('127.0.0.1', 53505)
[Wed May 9 20:59:14 2018] 哆啦A梦
...连接来自: ('127.0.0.1', 53506)
[Wed May 9 20:59:27 2018] 蜡笔小新
...连接来自: ('127.0.0.1', 53507)
...连接来自: ('127.0.0.1', 53508)
[Wed May 9 20:59:50 2018] 银河唯一的秘密
...连接来自: ('127.0.0.1', 53509)
[Wed May 9 21:00:13 2018] 超人迪加
...连接来自: ('127.0.0.1', 53510)
[Wed May 9 21:00:35 2018] 护卫人类,挽救地球,看守这宇宙
...连接来自: ('127.0.0.1', 53514)
end
参考:
http://www.cnblogs.com/Eva-J/
《python核心编程第四版》
铁乐学Python_Day35_Socket模块3和hmac模块的更多相关文章
- 铁乐学python_Day39_多进程和multiprocess模块2
铁乐学python_Day39_多进程和multiprocess模块2 锁 -- multiprocess.Lock (进程同步) 之前我们千方百计实现了程序的异步,让多个任务可以同时在几个进程中并发 ...
- 铁乐学python_Day38_多进程和multiprocess模块1
铁乐学python_Day38_多进程和multiprocess模块1 [进程] 运行中的程序就是一个进程. 所有的进程都是通过它的父进程来创建的. 因此,运行起来的python程序也是一个进程,那么 ...
- 铁乐学Python_Day34_Socket模块2和黏包现象
铁乐学Python_Day34_Socket模块2和黏包现象 套接字 套接字是计算机网络数据结构,它体现了C/S结构中"通信端点"的概念. 在任何类型的通信开始之前,网络应用程序必 ...
- 铁乐学Python_Day33_网络编程Socket模块1
铁乐学Python_Day33_网络编程Socket模块1 部份内容摘自授课老师的博客http://www.cnblogs.com/Eva-J/ 理解socket Socket是应用层与TCP/IP协 ...
- 铁乐学python_day25_序列化模块
铁乐学python_day25_序列化模块 部份内容摘自博客http://www.cnblogs.com/Eva-J/ 回顾内置方法: __len__ len(obj)的结果依赖于obj.__len_ ...
- 铁乐学python_day28_模块学习3
大部份内容摘自授课老师的博客http://www.cnblogs.com/Eva-J/ OS模块复习一二 >>> import os >>> os.getcwd() ...
- hash模块 hashlib 和hmac
hashlib模块 用于加密相关的操作,代替md5模块和sha模块,主要提供SHA1,SHA224,SSHA256,SHA384,SHA512,MD5算法 直接看代码案例: ---------md5- ...
- Python之数据加密与解密及相关操作(hashlib模块、hmac模块、random模块、base64模块、pycrypto模块)
本文内容 数据加密概述 Python中实现数据加密的模块简介 hashlib与hmac模块介绍 random与secrets模块介绍 base64模块介绍 pycrypto模块介绍 总结 参考文档 提 ...
- python hashlib、hmac模块
一.hashlib模块 import hashlib m = hashlib.md5() m.update(b"Hello") print(m.hexdigest()) m.upd ...
随机推荐
- mysql中难以理解的sql
工作中遇到这样的例子, CASE type WHEN 1 THEN '普通红包' WHEN 2 THEN '普通礼包加油卡' WHEN 3 THEN '优 惠码兑换加油卡' WHEN 4 THEN ' ...
- Node.js数据流Stream之Readable流和Writable流
一.前传 Stream在很多语言都会有,当然Node.js也不例外.数据流是可读.可写.或即可读又可写的内存结构.Node.js中主要包括Readable.Writable.Duplex(双工)和Tr ...
- cordova打包APK,SyntaxError: Block-scoped declarations (let, const, function, class) not yet supported outside strict mode ...
javascript 严格模式 第一次接触let关键字,有一个要非常非常要注意的概念就是”javascript 严格模式”,比如下述的代码运行就会报错: let hello = 'hello worl ...
- java课件运行实践
两数相加 源文件:Addition.java 源代码: // An addition program import javax.swing.JOptionPane; // import class ...
- 浅谈JS中的!=、== 、!==、===的用法和区别
var num = 1; var str = '1'; var test = 1; test == num //true 相同类型 相同值 test === num ...
- Message小结(二)
当客户端调用一个WCF接口时,客户端将请求消息发送到服务端,服务端再返回回复消息.WCF内部实现了消息处理的所有细节,但是并不意味着一切不可更改.WCF也提供了一些方法让开发人员在消息发送前对消息进行 ...
- idea中maven项目程序包找不到解决办法之一
首先检查maven配置对不对,包括被settings文件以及资源库的位置,maven版本等. 如果不行的话再进行下面的操作: 第一种方案: 在终端terminal中项目目录下,输入“mvn idea: ...
- SPA应用部署时首屏启动慢问题解决方案
SPA应用部署时首屏启动慢问题解决方案 使用vuejs开发的单页应用,打包部署上线后,发现首屏启动时间达到了惊人的10s左右,于是开始优化,目前使用到的总结如下: 巧用webpack插件 1.抽取cs ...
- ASP.NET Core 2 学习笔记(十一)Cookies & Session
基本上HTTP是没有记录状态的协定,但可以通过Cookies将Request来源区分出来,并将部分数据暂存于Cookies及Session,是写网站常用的用户数据暂存方式.本篇将介绍如何在ASP.NE ...
- Linux学习7-Linux常用命令(3)
文件处理命令 命令名称:touch 命令英文原意:touch 命令所在路径:/bin/touch 执行权限:所有用户 功能描述:创建空文件 语法:touch[文件名] 范例: $tou ...