首先我还是要强调不管任何相同的字符串通过hashlib加密之后都会产生相同的32位字符串,这个是日常Web中常用的加密算法如果我的client发送一个请求过来我server接受到后就要对该密码进行判断,正常的流程是我需要把client端发送过来的请求转换成hashlib格式的字符串跟我存在数据库中的字符串进行对比做判断,当前我也可以在这些字符串加密前加盐(key)

以下是我的基础的server代码

代码解析:

首先我们需要明白Tcp下的服务端的7步曲

1.实例化socket对象

sk = socket.socket()

2绑定对应的服务器IP地址以及对外开放的端口

sk.bind(("127.0.0.1",8888))

3启动监听等待用户访问

sk.listen()

4建立tcp下的基本连接协议

conn,addr = sk.accept()

#5通讯的逻辑

rse = conn.recv(1024)#指定接收1024的字符串

conn.send("相信你自己就是最牛逼的哪一个".decode("utf-8"))

#6四次挥手断开连接

conn.close()

#7退还端口

sk.close()

这就是基础的服务端的代码

下面我要对服务端进行改造改造代码如下

# ### 服务器
import socket
import hmac
import os def auth(conn,secret_key):
# 随机的32位二进制字节流
res = os.urandom(32)
# 把res发送给对方的服务器
conn.send(res)
# 用hmac加密字符串
hm = hmac.new(secret_key.encode(),res)
# 通过hexdigest返回32长度的十六进制字符串
res_server = hm.hexdigest()
print(res_server) # 接受客户端发过来的加密后的字符串
res_cli = conn.recv(1024).decode("utf-8") if res_server == res_cli:
print("该用户是合法的链接请求")
return True
else:
print("该用户是非法的链接请求")
return False # 创建对象
sk = socket.socket()
sk.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
sk.bind( ("127.0.0.1",9001) )
sk.listen()
conn,addr = sk.accept() # 收发数据的逻辑
secret_key = "ig不牛逼"
# 调用函数,验证权限
res = auth(conn,secret_key)
# 如果验证的结果是真的,就处理用户发送过来的请求,假的直接断开链接
if res:
print(conn.recv(1024).decode("utf-8")) conn.close()
sk.close()

注os.urondom()是os模块下的一种方法,随机产生指定位数的随机2进制字节流

此时我对收发逻辑做了一定的处理下面我为为我写的auth代码进行解析

自定义一个auth权限函数,该函数需要2个变量conn(客户端返回服务端的端口对象或链接对象),secret_key(盐也就是我要key )

1  在auth里面我随机生成了一个指定32位随机2进制字节流os.urandom(32)

2 我需要把我服务端生成的32位随机季节流发送给服务端 conn.send(res)

3 用hmac加密hmac.new(secret_key.encode(),res)  俩个参数(一个是我需要加入的盐,另外一个是我生成的32位随机2进制流)

通过hmac的加密我会产生一个新的数据流 而这个数据流与客户端发送过来的数据流是一致的话那么我就可以认为此时的数据所对应的结果是一致的密码匹配成功

4 接受客户端加密后的密码串进行反解

5 验证客户端的加密是否与服务端的加密内容是否一致

6返回判断的内容

如果auth判断的结果是Ture那么我就直接给客户端返回这个登录状态登录成功

否则则给客户端返回一个登录失败的状态

关闭连接

退还端口

客户端的代码

是首先需要对socket进行引入

import socket

sk = socket.socket()#实例化socket对象

sk .connect(("127.0.0.1",8888))#指定相对应的服务器访问

sk.send("相信你自己是最牛逼的哪一个".encode())#对服务器发送请求

res = sk.recv(1024).decode("utf-8")接受服务端给我返回的消息

sk.close()#退还端口

下面我队我客户端的代码进行优化

# ### 客户端
import socket
import hmac def auth(sk,secret_key):
# 收发数据的逻辑
msg = sk.recv(32)
# 把key 和 msg 扔到new当中,进行加密
hm = hmac.new(secret_key.encode(),msg)
# 通过hexdigest把加密后的结果返回出来
res_cli = hm.hexdigest()
print(res_cli)
# 把加密好的字符串在发送回原服务器
sk.send(res_cli.encode()) sk = socket.socket()
sk.connect( ("127.0.0.1",9001) ) secret_key = "ig不牛逼"
# 调用函数,验证权限
auth(sk,secret_key)
# 向服务器发出下载的请求
sk.send(b"download") # 关闭链接
sk.close()

首先基于原始的client与服务端的通信下我对我的收发数据的逻辑进行了改造

自定义一个auth权限函数,该函数需要2个变量sk(客户端要与服务端的端口对象或链接对象),secret_key(盐也就是我要key )

1 我需要把我客户端接受服务端给我发送的32位随机2进制流 sk.recv(32)

3 用hmac加密hmac.new(secret_key.encode(),res)  俩个参数(一个是我需要加入的盐,另外一个是我生成的32位随机2进制流)

通过hmac的加密我会产生一个新的数据流 而这个数据流我会发送给服务端数,如果我客户端收缩加密的字节流与服务端加密的是一致的话我会得到服务端的校验判定

sk.close()#退还端口

传统简易的server与client登录验证交互

server代码

基于上面的代码我现在扩展模拟到数据库中取出我的账号以及密码并且对服务端发送过来的账户密码进行验证,如果验证成功我就给客户端返回登录状态

以下是代码

# ### 服务端
import hashlib
import socket
import json def get_md5_code(usr,pwd):
# 将用户名作为加密的盐key
hm = hashlib.md5(usr.encode())
hm.update(pwd.encode())
res = hm.hexdigest()
return res sk = socket.socket()
sk.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
sk.bind( ("127.0.0.1",9000) )
sk.listen()
conn,addr = sk.accept() # 处理收发数据的逻辑
# 先接受二进制字节流 -> 字符串
msg = conn.recv(1024).decode()
print(msg,type(msg))
# 把字符串 -> 字典
dic = json.loads(msg)
print(dic,type(dic)) # 标识符,默认False
sign = False
with open("userinfo.txt",mode="r",encoding="utf-8") as fp:
for line in fp:
usr,pwd = line.strip().split(":")
if usr == dic["username"] and pwd == get_md5_code(dic["username"],dic["password"]):
# 登陆成功 返回状态吗为1
res = {"code":1}
res_msg = json.dumps(res).encode()
conn.send(res_msg)
# 如果登录成功,默认改成True
sign = True
break if sign == False:
#登录失败,返回状态码为0
res = {"code":0}
conn.send(json.dumps(res).encode()) # 四次挥手
conn.close()
# 退还端口
sk.close()

代码解析

def get_md5_code(usr,pwd):
# 将用户名作为加密的盐key
hm = hashlib.md5(usr.encode())
hm.update(pwd.encode())
res = hm.hexdigest()
return res
这里代码的主要作用是把用户名作为盐(key),pwd作为要加密的字符串
返回的是一个加盐(key)后的随机32位字符串,当我收到客户端的数据后需要经过json 字符串的反解后得到的一个字典,该字典包含了密码以及用户名的一种数据
此时我需要把字典的用户名以及密码拿出来做加密后跟数据库所存的随机字符串做比对,如果比对成功那么我就会给客户端返回一个状态反之给客户端返回一个否定的状态
下面我要介绍我的客户端的代码
# ### 客户端
import socket
import json
sk = socket.socket()
sk.connect( ("127.0.0.1",9000) ) usr = input("请输入您的账户:")
pwd = input("请输入您的密码:")
dic = {"username":usr,"password":pwd,"operate":"login"}
# 返回json格式的字符串
res = json.dumps(dic)
# 在把json字符串转换成字节流
bytes_msg = res.encode()
# 发送给服务端
sk.send(bytes_msg) # 接受服务端发送回来的数据
res_msg = sk.recv(1024).decode()
# 把字符串变成字典
dic_code = json.loads(res_msg) if dic_code["code"]:
print("恭喜你,登陆成功")
else:
print("抱歉,登陆失败") # 关闭链接
sk.close()

首先在客户端中我要生成一个字典,字典里面包含了我的账户以及密码名我通过json下的dumps强制把字典转换为json类型的字符串,通过这个字符串我直接发给服务端,让服务端帮我操作,如果匹配成功那么我就返回一个已经登录的状态,反之登录失败


 

hashlib(hmac)进阶之client跟server交互的更多相关文章

  1. 深入浅出 Redis client/server交互流程

    综述 最近笔者阅读并研究redis源码,在redis客户端与服务器端交互这个内容点上,需要参考网上一些文章,但是遗憾的是发现大部分文章都断断续续的非系统性的,不能给读者此交互流程的整体把握.所以这里我 ...

  2. Python——常用模块(time/datetime, random, os, shutil, json/pickcle, collections, hashlib/hmac, contextlib)

    1.time/datetime 这两个模块是与时间相关的模块,Python中通常用三种方式表示时间: #时间戳(timestamp):表示的是从1970年1月1日00:00:00开始按秒计算的偏移量. ...

  3. [从源码学设计]蚂蚁金服SOFARegistry 之 如何与Meta Server交互

    [从源码学设计]蚂蚁金服SOFARegistry 之 如何与Meta Server交互 目录 [从源码学设计]蚂蚁金服SOFARegistry 之 如何与Meta Server交互 0x00 摘要 0 ...

  4. UDP编程中client和server中使用recvfrom和sendto的区别

    client中:      sendto(sfd,buf,strlen(buf),0,(struct sockaddr *)&saddr,len);      recvfrom(sfd,buf ...

  5. tmux protocol version mismatch (client 7, server 6)

    $ tmux attach protocol version mismatch (client 7, server 6) $ pgrep tmux 3429 $ /proc/3429/exe atta ...

  6. New full duplex HTTP tunnel implementation (client and server)

    https://issues.jboss.org/browse/NETTY-246?page=com.atlassian.jirafisheyeplugin:fisheye-issuepanel —— ...

  7. jvm的client和server

    最近研究c++代码调用java的jar,发现64位的下的jvm在server路径,而32位的jvm则存在client路径下面,于是十分好奇,查了下,这里做个记录 JVM Server模式与client ...

  8. Android简单的聊天室开发(client与server沟通)

    请尊重他人的劳动成果.转载请注明出处:Android开发之简单的聊天室(client与server进行通信) 1. 预备知识:Tcp/IP协议与Socket TCP/IP 是Transmission ...

  9. 【Python】 hash值计算 hashlib & hmac

    hashlib & hmac *不是很清楚能不能把这种hash值取样算法称之为加密,但是似乎好像也是这么说的哈(非科班出身的野路子就是没这种基本知识的) ■ 基本用法 hashlib支持MD5 ...

随机推荐

  1. SQL注入漏洞技术的详解

    SQL注入漏洞详解 目录 SQL注入的分类 判断是否存在SQL注入 一:Boolean盲注 二:union 注入 三:文件读写 四:报错注入 floor报错注入 ExtractValue报错注入 Up ...

  2. [Go] gocron源码阅读-groutine与channel应用到信号捕获

    直接使用go 函数名()可以开启一个grountine,channel可以接收信息并且如果没有数据时会阻塞住channel对应的是底层数据结构的引用,复制channel和函数传参都是拷贝的引用make ...

  3. Ubuntu 18.04安装Conda、Jupyter Notebook、Anaconda

    1.Conda是一个开源的软件包管理系统和环境管理系统,它可以作为单独的纯净工具安装在系统环境中,有的python库无法用conda获得时,conda允许在conda环境中利用Pip获取包文件.可以将 ...

  4. 23.Java基础_ArrayList类

    ArrayList类的构造和使用方法 import java.util.ArrayList; public class test { public static void main(String[] ...

  5. 有用的link

    资料 了解oi 刘汝佳代码仓库(紫书 c++参考手册 2018年洛谷日报索引 2019年洛谷日报索引 (其他oj: luogu 虚拟判官(名校oj都有 离线bzoj题库 (有时候进不去请点:rxz大爷 ...

  6. Html学习之五(嵌套之简单购物界面设计)

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  7. pycharm 远程连接

    1.连接远程项目 2.连接远程服务器

  8. (day55)七、查询优化、MTV和MCV、choices、AJAX、序列化

    目录 一.ORM查询优化 (一)only与defer (1)only (2)defer (二)select_related与prefatch_related (1)select_related (2) ...

  9. JS分类选择插件

    需要做一个选择分类工具,大致要求如下: 点击按钮,显示一级分类,指向某个一级分类显示对应二级分类,分类有几层不定. 只能选择最后一个分类,然后把分类的ID 传值给按钮的value 我的思路: 1.后台 ...

  10. Flutter基础系列之入门(一)

    1.Flutter是什么? 官方介绍:Flutter是谷歌的移动UI框架,可以快速在iOS和Android上构建高质量的原生用户界面. Flutter可以与现有的代码一起工作.在全世界,Flutter ...