背景:
由于公司安全规范限制,我司的测试、预发布、灰度、生产环境,接口间的数据通信通常是加密处理的,给我们日常定位缺陷带来了一定的阻碍,因此我决定使用Python写一个工具,将加密数据转换为正常数据,便于日常问题定位。
由于是第一次写页面化的测试工具,我将把自己的思路做完整的记录,便于日后回归以及套用。
工具开发思路:
1.先使用Python,根据安全规则,实现接口间数据的解密方法
2.使用flask框架,将接口间的数据解密方式封装成接口,并且能在本地正常调试
3.使用HTML编写工具的静态页面
4.使用HTML调用封装的接口,从而完成工具的开发
具体实现:
一、 安全规则为:
1.客户端使用aes密钥去加密接口入参,生成密文1
2.客户端使用rsa的公钥去加密aes密钥生成密文2
3.客户端向服务端发送请求的时候,会将密文1、密文一并传输到服务端
4.服务端使用rsa的私钥去解密密文1,得到aes的密钥
5.服务到使用步骤4解密出来的aes密钥,去解密密文2,得到接口的入参
根据数据间的加解密规则可以看出,安全规则的加密规范是rsa+aes混合加密,其中aes是对称加密,rsa是非对称加密。对称加密简单的来说是可以通过一个密钥完成数据的加解密,非对称加密是使用公钥加密,私钥解密。
我们能够在接口的入参和header头中获取到已加密的信息,因此我们仅需要关注解密过程(安全规则的4、5步骤)
二、实现rsa解密&aes解密:
想要实现rsa解密,需要获取2个关键信息:
1.rsa的私钥
2.需要解密的信息
具体代码实现如下:
def decode_by_rsa(self, **my_json):
'''
解密
'''
rsa_key = '-----BEGIN RSA PRIVATE KEY-----\n' + my_json["body"]["rsa_key"] + '\n -----END RSA PRIVATE KEY-----'
message_info = my_json["body"]["message_info"]
try:
if rsa_key and message_info != '':
pri_key = RSA.importKey(rsa_key)
cipher = PKCS1_cipher.new(pri_key)
back_text = cipher.decrypt(base64.b64decode(message_info), 0)
return responseData.response(200, "解密成功", {'data': back_text.decode('utf-8')})
elif rsa_key or message_info == '':
return responseData.response(-1, "解密失败", {'data': "参数不能为空!"})
except Exception as e:
return responseData.response(-1, "解密失败", {'data': f"参数格式错误:{e}"})
想要实现aes解密,需要知道3个关键信息
1.aes密钥
2.待解密信息
3.加密模式
具体实现代码如下:
def decode_by_aes(self, **my_json): # **my_json 使用** 将入参封装成一个字典
'''
aes解密
'''
message_info = my_json["body"]["message_info"]
aes_key = my_json["body"]["aes_key"]
try:
if aes_key and message_info != "":
script_key = aes_key.encode('utf-8')
mode = AES.MODE_ECB
cryptor = AES.new(script_key, mode)
res = cryptor.decrypt(base64.decodebytes(message_info.encode("utf-8")))
# 去除填充
un_padded_data = unpad(res, AES.block_size, style='pkcs7')
return responseData.response(200, "解密成功", {'data': un_padded_data.decode('utf-8')})
elif aes_key or message_info == "":
return responseData.response(-1, "解密失败", {'data': "参数不能为空!"})
except Exception as e:
return responseData.response(-1, "解密失败", {'data': f"参数格式错误:{e}"})
三、使用flask框架将对应的方法封装成接口
1.将解密方法封装到一个类中,并将该类置于flask框架的Common层
2.在根目录创建一个.py文件,充当程序入口
from flask import Flask, render_template, jsonify, request
from flask_cors import CORS
from Common.encryption_and_decryption_tool import EncryptionAndDecryption
app = Flask(__name__, static_url_path=None, static_folder='static')
# static_folder这里是在指定静态资源的文件夹,因此需要与框架中的静态资源文件名称保持一致
CORS(app) # 跨域资源共享,避免游览器安全策略限制,导致接口端口号发生更改
app.config["JSON_AS_ASCII"] = False # 确保返回的json字符串中中文可以正常显示
@app.route('/', methods=["GET", "POST"]) # 定义接口的路径和支持的请求方法
def index():
return render_template("tool.html") # 跳转至指定的静态资源页面
@app.route("/decode_api", methods=["GET", "POST"])
def decode_api():
try:
my_json = request.get_json() # 从前端请求种获取json格式的数据,并将其存储到变量my_json中
return getattr(EncryptionAndDecryption(), my_json['pubRequest']['method'])(**my_json)
# 这样写是为了兼容我司接口入参规范,具体规范参照本地调试的入参格式
# 这行代码使用 getattr() 函数获取 EncryptionAndDecryption() 实例对象的某个方法,并根据传入的 my_json 参数中的 pubRequest
# 字段的 method 值来决定调用哪个方法。**my_json 则是将 my_json 参数中的所有键值对作为关键字参数传递给该方法
except Exception as e: # 使用try ...except 对异常进行处理,保证程序能完整执行,不会因为异常而中断
return f"请求错误{e}"
if __name__ == '__main__':
app.run(host="0.0.0.0", debug=True, port=5000)
# host:指定服务器绑定的IP地址,默认为"127.0.0.1",即本地回环地址。如果要让服务器能够被其他计算机访问,可以将它设置为"0.0.0.0"。
# port:指定服务器监听的端口号,默认为5000
# debug:启用调试模式,当代码发生错误时,会输出详细的错误信息和堆栈跟踪,便于调试和开发。
本地调试:
1.在本地运行.py的文件。将本机作为一台服务器,运行结果如下
2.使用postman进行本地调试(由于公司的接口入参规范,因此我这里是按照我司的入参规规范进行调试的):
四、编写html静态页面:
我这个桌面工具的功能很简单,就是为了实现加密字符串的解密,因此我们的样式设置如下:
功能描述:清除--将输入的内容全部删除;解析---根据输入内容去解密已加密的字符串
五、页面调用对应接口,完成工具开发
1.使用 XMLHttpRequest 对象向服务器发送请求
2.引入对应的js文件,给按钮绑定点击事件
3.页面效果及功能展示:
小结:
这次小工具的开发,我使用到了Python的flask框架还有HTML,学会了HTML页面调用接口的方法,但是暂未实现前后端分离。这是我的第一个测试小工具,虽然很简单,但是在实现过程中还是遇到了很多问题,在解决这些问题的时候,我收获了不少知识。该文章仅做笔记使用,便于自己日后复习。
--------------------------------------------学海无涯