常见加密方式
## 摘要算法:MD5、SHA
消息摘要算法的主要特征是加密过程不需要密钥,并且理论上经过加密的数据无法被解密,加密之后的密文长度是固定的,比较容易被破解掉,简单的密码很容易破解。主要是为了校验数据在传输过程中是否被修改,应用场景:密码
加密、文件校验 【哈希算法】
[MD5在线加密](https://www.sojson.com/encrypt_md5.html):https://www.sojson.com/encrypt_md5.html
## base64编码 【要进行编码之前一定要转化二进制数据】
Base64编码将二进制数据转换为可打印字符,主要用于在传输过程中处理二进制数据。在接口测试中,有时会使用base64编码对加密后的数据进行编码以便于传输。
注意:base64编码并不是一种加密算法,而是一种编码方式,不能提供真正的加密功能,在项目中往往是结合其他加密算法一起使用。【先加密再编码】
[在线base64编码解码工具](https://www.toolhelper.cn/EncodeDecode/Base64EncodeDecode):
https://www.toolhelper.cn/EncodeDecode/Base64EncodeDecode
加密算法:AES、DES,RSA
- 对称加密算法:加密和解密使用相同密钥的算法: 安全性比较低,密码容易泄露,但是速度比较快。【AES、DES算法】
- 非对称加密算法:两个密钥,公钥【加密】和私钥【解密】,分别用于加密和解密数据,公钥可以被任何人使用,私钥只能被数据持有者使用【服务器】。【非对称加密算法:RSA(公钥、私钥)】 ==用的更多【SSH】
## Python提供丰富的加密库,包括base64、hashlib、crypto等,可以直接用于处理加密数据。
- base64库:适用于base64编码,自带库 不需要安装 直接导入使用
- hashlib库: 适用于MD5、SHA1、SHA256加密 自带库 不需要安装 直接导入使用
- crypto:适用于AES、DES,RSA, `pip install pycryptodome`是一个第三方库,安装并导入使用。
## 接口加密项目案例实战
### MD5加密
特别需要注意:MD5是不能解密的,加密是不可逆的。其实是一种hash算法,不可逆。
为什么一些在线网站提供了MD5解密功能?
- 因为网站会把一些常用数据及对应的MD5加密密文存储到数据库中
- 你输入在数据库有的密文的信息,就可以获取到原始的数据;所以一般常用的密码 就和容易被破解了。
MD5加密的代码语法:使用的内置库:hashlib,直接导入使用。
- 准备好明文
- 第一步:讲明文数据转换为二进制数据 【注意加密和编码都需要是二进制数据】
- 第二步:进行MD5加密数据
- 第三步:密文用于发送接口测试
import hashlib
data = 'lemonban'
data_bytes = data.encode('utf-8')
# 使用md5进行加密
md5 = hashlib.md5(data_bytes).hexdigest()
MD5加密算法实例 --ERP项目 登录接口
- 接口信息
- 请求方式:POST
- 请求地址:http://erp.lemfix.com/user/login
- 请求头:"Content-Type","application/x-www-form-urlencoded"
- 请求体参数:
loginame=admin&password=e10adc3949ba59abbe56e057f20f883e
# erp项目的MD5加密演示
import hashlib
import requests
data = '123456' # 要加密的原始字符串
# 第一步:因为数据是文本类型,所以我们需要转换为二进制
data_bytes = data.encode('utf-8')
# 第二步:通过hashlib进行加密
encrypt_pwd = hashlib.md5(data_bytes).hexdigest()
# 第三步:密文用于接口测试
url = 'http://erp.lemfix.com/user/login'
body_params = {'loginame':'admin','password':encrypt_pwd}
res = requests.post(url,data=body_params)
print(res.text)
范例:
"""
hashlib库: 适用于MD5、SHA1、SHA256加密 自带库 不需要安装 直接导入使用
* 第一步:把明文数据转换为二进制数据 【注意加密和编码都需要是二进制数据】
* 第二步:对二进制数据进行MD5加密数据
* 第三步:密文用于发送接口测试
"""
import hashlib
import requests
# ERP项目实战 --密码进行MD5的加密之后接口参数的传输
pwd = "123456"
# 第一步:把明文数据转换为二进制数据: encode方法把字符串转化为二进制数据
data_bytes = pwd.encode("UTF8")
# 第二步:对二进制数据进行MD5加密数据
md5_pwd = hashlib.md5(data_bytes).hexdigest()
# 第三步:密文用于发送接口测试
url = "http://erp.lemfix.com/user/login"
params = {"loginame":"test123","password":md5_pwd}
resp = requests.request(method="post",url=url,data=params)
print(resp.text)
### base64
如果接口的参数开发进行了base64编码,那我们做接口测试需要先对数据进行编码再传递给接口,base64可以对文字数据+ 图片数据 进行编码。【图片验证码】
使用的是内置库: base64, 直接导入可以使用。
base64编码的操作分为3步骤:
这是base64编码的前提条件
- 第一步: 将原始数据转化为二进制数据 ,因为base64编码和解码都需要数据是二进制格式。 【 这是base64编码的前提条件】
- 第二步: 把第一步的二进制的数据进行base64编码 ,得到编码后的二进制数据
- 第三步: 讲编码后的二进制数据转化回 字符串,用于后续的接口参数传递。
base64可以对文字数据进行编码
import base64
data = "lemon1234" # 要编码的原始字符串
# 第一步: 将原始数据转化为二进制数据 ,因为base64编码和解码都需要
数据是二进制格式。
data_byte = data.encode("utf8")
# 第二步: 把第一步的二进制的数据进行base64编码 ,得到编码后的二
进制数据
b64_byte = base64.b64encode(data_byte)
# 第三步: 将编码后的二进制数据转化回字符串格式,用于后续的接口参
数传递
data_str = b64_byte.decode("UTF8")
print(data_str)
```
对图片进行base64编码,数据本身就是二进制,可以省略第一步。
```python
import base64
# 第一步:open方法打开图片,得到二进制数据
with open("tricy.png","rb") as f:
pic_data = f.read() # 这样得到的本身就是二进制数据
# 第二步:进行二进制数据的base64编码
b64_data = base64.b64encode(pic_data)
# 第三步:转化为字符串类型用于接口测试
b64_str = b64_data.decode("UTF8")
print(b64_str)
范例:
"""
base64库:适用于base64编码,自带库 不需要安装 直接导入使用
base64编码的操作分为3步骤:
第一步: 将原始数据转化为二进制数据 ,因为base64编码和解码都需要数据是二进制格式。 【这是base64编码的前提条件】
第二步: 把第一步的二进制的数据进行base64编码 ,得到编码后的二进制数据
第三步: 讲编码后的二进制数据转化回 字符串,用于后续的接口参数传递。
"""
import base64
# base64对文字数据编码
# data = "lemon1234" # 原始数据
# # 第一步: 将原始数据转化为二进制数据
# data_bytes = data.encode("utf8")
# print(data_bytes)
# # 第二步: 把第一步的二进制的数据进行base64编码 ,得到编码后的二进制数据
# b64_bytes = base64.b64encode(data_bytes)
# print(b64_bytes)
# # 第三步: 把编码后的二进制数据转化回字符串,用于后续的接口参数传递。
# b64_str = b64_bytes.decode("utf8")
# print(b64_str)
# base64对图片数据编码
with open("tricy.png","rb") as f:
pic_data = f.read() # 读取图片之后 是一个二进制数据b''
# 第二步: 把第一步的二进制的数据进行base64编码 ,得到编码后的二进制数据
b64_data = base64.b64encode(pic_data)
# 第三步: 把编码后的二进制数据转化回字符串,用于后续的接口参数传递。
b64_str = b64_data.decode("UTF8")
print(b64_str)
### RSA加密算法的代码实现【非对称加密】
更多的项目会使用更加复杂的加密算法,比如RSA非对称加密,安全性更高。
如果项目用的非对称加密算法加密的话,应该怎么做?
RSA算法会有公钥及私钥:公钥->加密,私钥->解密,我们需要以下准备工作:
- 第一步:可以去找开发去拿公钥(公开的)[一般以pem结尾的文件]
- 第二步:对应python库进行加密,使用公钥加密。
RSA加密算法的代码实现。crypto第三方库 自己安装。
`pip install pycryptodome`
- 代码是复用的 不理解也没关系,直接复制可以直接使用。
步骤如下:【RSA一般都会结合base64编码一起使用的】
第一步:读取公钥信息内容
第二步:通过RSA导入公钥信息,并返回公钥对象
第三步: 基于公钥创建RSA加密器对象
第四步:通过RSA加密器对象进行加密(加密前数据转换为二进制格式)
第五步:需要先进行base64编码,才可以转化为字符串可用文本
第六步: 将二进制数据转化为文本
import base64
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
data = "12345" # 待加密的数据
data_bytes = data.encode("UTF8") #转化为二进制数据
# 第一步:读取公钥信息内容
with open("rsa_public_key.pem") as f:
public_key_str = f.read()
# 第二步:通过RSA导入公钥信息,并返回公钥对象
public_key = RSA.importKey(public_key_str)
# 第三步: 基于公钥创建RSA加密器对象
pk = PKCS1_v1_5.new(public_key)
# 第四步:通过RSA加密器对象进行加密(加密前数据转换为二进制格
式)
rsa_data = pk.encrypt(data_bytes) # 这个是二进制的数据
# 第五步:需要先进行base64编码,才可以转化为字符串可用文本
base64_data = base64.b64encode(rsa_data)
# 第六步: 将二进制数据转化为文本
print(base64_data.decode("UTF8"))
rsa加密算法代码的函数封装: 把加密数据 和公钥参数化, 返回解密后的的数据。供后续直接使用。
d4_handle_encrypt.py
import base64
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
def encrypt_with_rsa(data, public_key_path):
data_bytes = data.encode('utf-8')
with open(public_key_path) as f:
# 1、从公钥读取对应的数据
public_key_data = f.read()
# 2、通过RSA导入公钥数据,并且返回公钥对象
public_key = RSA.importKey(public_key_data)
# 3、创建RSA加密器对象
rsa = PKCS1_v1_5.new(public_key)
# 4、通过RSA加密器进行加密(加密前的数据也需要保证是二进制格式的)
rsa_data = rsa.encrypt(data_bytes)
# 5、进行base64编码
base64_data = base64.b64encode(rsa_data)
# 6、将二进制数据转换为文本即可
return base64_data.decode('utf-8')
RSA加密算法实例 --前程贷接口登录
登录接口
- 请求方式:POST
- 接口地址:http://api.lemonban.com:8788/futureloan/member/login
- 请求头:
- "X-Lemonban-Media-Type","lemonban.v3"
- "Content-Type","application/json"
- 请求体参数:{"mobile_phone": "13323231111","pwd": "12345678"}
充值接口
- 请求方式:POST
- 接口地址:http://api.lemonban.com:8788/futureloan/member/recharge
- 请求头:
- "X-Lemonban-Media-Type","lemonban.v3"
- "Content-Type","application/json"
- "Authorization","Bearer token" (从登录接口拿到token,特别注意:Bearer前缀与token之间有空格)
- 请求体参数:{"member_id": XXX,"amount": 10000.0,"timestamp":XXX,"sign": "XXX"}
范例:
"""
登录接口
* 请求方式:POST
* 接口地址:http://api.lemonban.com:8788/futureloan/member/login
* 请求头:
* "X-Lemonban-Media-Type","lemonban.v3"
* "Content-Type","application/json"
* 请求体参数:{"mobile_phone": "13323231111","pwd": "12345678"}
充值接口: 先登录再操作,接口鉴权【鉴别用户权限】
* 请求方式:POST
* 接口地址:http://api.lemonban.com:8788/futureloan/member/recharge
* 请求头:
* "X-Lemonban-Media-Type","lemonban.v3"
* "Content-Type","application/json"
* "Authorization","Bearer token" (从登录接口拿到token,特别注意:Bearer前缀与token之间有空格)
* 请求体参数:{"member_id": XXX,"amount": 10000.0,"timestamp": XXX,"sign": "XXX"}
鉴权规则: timestamp+token+sign 方式
"""
import requests
from jsonpath import jsonpath
import time
from d4_handle_encrypt import encrypt_rsa
# 登录接口
url = "http://api.lemonban.com:8788/futureloan/member/login"
header = {"X-Lemonban-Media-Type":"lemonban.v3","Content-Type":"application/json"}
params = {"mobile_phone": "13323231111","pwd": "12345678"}
resp = requests.request(method="post",url=url,headers=header,json=params)
print("登录接口",resp.json())
# 提取token memberid
token = jsonpath(resp.json(),"$..token")[0]
member_id = jsonpath(resp.json(),"$..id")[0]
print(token)
# 获取秒级时间戳
timestamp = int(time.time()) # 微妙级别的时间戳,取整
# token字段前50位再拼接上timestamp值
token_sub = token[0:50] # token字段前50位
data = f"{token_sub}{timestamp}" # 需要被加密的明文
# 对data 通过RSA公钥加密得到的字符串- sign参数要传的值
sign = encrypt_rsa(data,"rsa_public_key.pem")
# 充值接口
url = "http://api.lemonban.com:8788/futureloan/member/recharge"
header = {"X-Lemonban-Media-Type":"lemonban.v3","Content-Type":"application/json",
"Authorization":f"Bearer {token}"}
params = {"member_id": member_id,"amount": 10000.0,"timestamp": timestamp,"sign": sign}
resp = requests.request(method="post",url=url,headers=header,json=params)
print("充值接口",resp.json())
###鉴权规则: timestamp+token+sign 方式
1. 设置 Authorization 请求头,值为 Bearer token 值
2. 请求体 json 设置 timestamp 参数,值为当前秒级时间戳
时间戳用来在计算机中记录时间的数值(从1970-1-1,0-0-0)总共经过了多少秒数,方便计算机处理
[在线时间戳网站](https://tool.lu/timestamp/):https://tool.lu/timestamp/
# 怎么去得到秒级别的时间戳-小数点前面的整数
print(int(time.time()))
```
```python
"""
时间戳:请求体 json 设置 timestamp 参数,值为当前秒级时间戳
"""
import time
timestamp = time.time() # 微妙级别的时间戳
print(int(timestamp))
```
3. 请求体 json 设置 sign 参数(签名),取 token字段 前 50 位再拼接上
timestamp 值,然后通过RSA 公钥加密得到的字符串
```python
token_sub_str = token[0:50] # token前50位,切片实现
data = f'{token_sub_str}{timestamp}' # 拼接 用格式化输出实
现
sign = encrypt_with_rsa(data, 'rsa_public_key.pem') # 调用
上面封装的rsa加密函数进行加密
总结,在实际的工作中如果碰到了接口参数加密应该怎么解
决:
1、找开发去沟通项目采用的加密的算法和加密策略,然后使用对应的方法和库
来解决。
2、MD5->Hashlib
base64->base64
RSA/AES/DES->crypto
- 非对称加密:还需要拿到公钥
- 对称加密: 秘钥
DES->pydes
# 图片验证码处理
【结合base64案例】
验证码的为了防止机器频繁访问网站的 防止爬虫 或者暴力破解这种, 验证你是
一个人操作 不是机器代码操作。公司内部做自动化测试的对于验证码的处理手段有如下几种:
1、让开发直接关掉验证码【 测试环境】,但是注意上线后要放开到生产环境里; =生产环境里还是要处理验证码的
2、让开发设置一个万能验证码,比如我们的系统lemon就是万能验证码,但是也是生产环境里要去掉 =生成环境里还是要处理验证码的
3、自己用代码处理验证码,这个比较复杂,需要有时间研究+ 并有代码技术能力,特别是遇到复杂变态的验证码 处理很麻烦,没有太大的必要 , 所以不推荐。
4、使用一些现有的验证码处理的网站(一般都是收费的网站)。
[图鉴](http://www.ttshitu.com/user/index.html):http://www.ttshitu.com/user/index.html
花钱 调用他的接口 公开给别人使用的文档
## 调用图鉴的接口操作处理后端的登录的验证码分为以下3个步骤:
1)拿到要处理的验证码图片
2)调用处理验证码的接口,获取验证码的内容。
3)登录接口,验证码传输值。
### 第一步: 抓包获取拿到要处理的验证码图片
接口地址:http://shop.lemonban.com:8108/captcha.jpg?uuid=3dbf7f64-1ba8-4976-8939-8b8c6e003b87
url = "http://shop.lemonban.com:8108/captcha.jpg"
res = requests.request("get",url)
print(res.content)
以上返回的就是图片验证码的二进制结果。如果要查看一下 可以写写入文件。
### 第二步: 调用处理验证码的接口,获取验证码的内容。
图片要先进行base64编码
b64_data = base64.b64encode(res.content)
b64_str = b64_data.decode("UTF8")
```
调用处理验证码的接口,获取验证码的内容
```python
url_tu = "http://api.ttshitu.com/predict"
data ={ "username": "tricy",
"password": "lemon123456",
"typeid": "3",
"image":b64_str}
res = requests.request("post",url_tu,json=data)
print(res.json())
code_value = res.json()["data"]["result"]
print(code_value)
### 第三步:登录接口,验证码传输值。
url = "http://shop.lemonban.com:8108/adminLogin"
data = {"principal":"student",
"credentials":"lemon!@666",
"imageCode":code_value}
header = {"locale":"zh_CN"}
resp = requests.request("post",url,headers=header,json=data)
print(resp.text)
注意: 这里有个问题,会报错验证码错误或者过期,是因为没有传uuid这个参数。没有办法把图片验证码和本次登录联系起来。所以,需要传这个uuid和sessionuuid 做为关联。这个是本接口的特点,不是通用的步骤。
获取uuid:使用uuid这个内置库
import uuid
print(uuid.uuid4())
uuid = str(uuid.uuid4()) # 转化为字符串的格式
获取图片验证码的接口需要传uuid 的参数:
url = "http://shop.lemonban.com:8108/captcha.jpg"
uuid_str= str(uuid.uuid4())
params = {"uuid":uuid_str}
res = requests.request("get",url,params=params)
其他步骤不变,登录的时候传参sessionuuid,值是这个uuid。
url = "http://shop.lemonban.com:8108/adminLogin"
data = {"principal":"student",
"credentials":"lemon!@666",
"imageCode":code_value,
"sessionUUID":uuid_str} # 传uuid1
header = {"locale":"zh_CN"}
resp = requests.request("post",url,headers=header,json=data)
print(resp.text)
范例:
"""
调用图鉴的接口操作处理后端的登录的验证码分为以下3个步骤:
1)拿到要处理的验证码图片
2)调用处理验证码的接口,获取验证码的内容。
3)登录接口,验证码传输值。
接口地址:http://shop.lemonban.com:8108/captcha.jpg?uuid=3dbf7f64-1ba8-4976-8939-8b8c6e003b87
- ?uuid=3dbf7f64-1ba8-4976-8939-8b8c6e003b87 == uudi是个啥 以及怎么处理 有什么作用?
"""
import requests
import base64
import uuid
# 得到uuid
uuid_value = str(uuid.uuid4())
# 第一步: 抓包获取拿到要处理的验证码图片
# 发送获取验证码的接口 返回响应结果是一个二进制的数据 --图片本身信息
url = "http://shop.lemonban.com:8108/captcha.jpg"
params = {"uuid":uuid_value}
res = requests.request("get",url,params=params)
print(res.content)
# 第二步:对图片的二进制的数据进行base64编码 -- 因为图鉴的接口需要对图片参数进行base64编码
b64_data = base64.b64encode(res.content)
b64_str = b64_data.decode("UTF8") # 转化字符串 用于接口传参
# 第三步:调用处理验证码的接口,获取验证码的内容
url_tu = "http://api.ttshitu.com/predict"
data ={ "username": "tricy",
"password": "lemon123456",
"typeid": "3",
"image":b64_str}
res = requests.request("post",url_tu,json=data)
code_value = res.json()["data"]["result"]
print(code_value)
# 登录接口
url = "http://shop.lemonban.com:8108/adminLogin"
data = {"principal":"student",
"credentials":"lemon!@666",
"imageCode":code_value,
"sessionUUID":uuid_value}
header = {"locale":"zh_CN"}
resp = requests.request("post",url,headers=header,json=data)
print(resp.text)