接口加密和图片验证码处理

常见加密方式

摘要算法:MD5、SHA

消息摘要算法的主要特征是加密过程不需要密钥,并且理论上经过加密的数据无法被解密,加密之后的密文长度是固定的,比较容易被破解掉,简单的密码很容易破解。主要是为了校验数据在传输过程中是否被修改,应用场景:密码
加密、文件校验 【哈希算法】
MD5在线加密:https://www.sojson.com/encrypt_md5.html

base64编码 【要进行编码之前一定要转化二进制数据】

Base64编码将二进制数据转换为可打印字符,主要用于在传输过程中处理二进制数据。在接口测试中,有时会使用base64编码对加密后的数据进行编码以便于传输。
注意:base64编码并不是一种加密算法,而是一种编码方式,不能提供真正的加密功能,在项目中往往是结合其他加密算法一起使用。【先加密再编码】
在线base64编码解码工具
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编码,数据本身就是二进制,可以省略第一步。

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在线编码的工具
https://www.toolhelper.cn/EncodeDecode/Base64EncodeDecode
适用于图片的base64编码在线工具:http://m.91tool.com/base64
范例:

"""
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/
# 怎么去得到秒级别的时间戳-小数点前面的整数
print(int(time.time()))
"""
时间戳:请求体 json 设置 timestamp 参数,值为当前秒级时间戳
"""
import time
timestamp = time.time()  # 微妙级别的时间戳
print(int(timestamp))
  1. 请求体 json 设置 sign 参数(签名),取 token字段 前 50 位再拼接上
    timestamp 值,然后通过RSA 公钥加密得到的字符串
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
花钱 调用他的接口 公开给别人使用的文档

调用图鉴的接口操作处理后端的登录的验证码分为以下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")

调用处理验证码的接口,获取验证码的内容

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)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值