一、soar-web部署
1.1 简介
soar-web是一款基于小米【SOAR】(https://github.com/XiaoMi/soar) 的开源 SQL 分析与优化的 web 图形化工具,支持 SOAR 配置的添加、修改、复制,多配置切换,配置的导出、导入与导入功能。
soar-web的github地址:https://github.com/xiyangxixian/soar-web
1.2 安装部署
python环境:需要安装python3.x
依赖包有3个,使用pip安装或者离线包安装。
Flask
pymysql
pycryptodome
离线安装采用下载soar-web的压缩包
https://codeload.github.com/xiyangxixian/soar-web/zip/master
解压后启动方式为执行run.sh。
二、soar-web的主要功能架构说明
2.1Flask框架简要说明
Flask是一个用Python编写的Web应用程序框架。Armin Ronacher带领一个名为Pocco的国际Python爱好者团队开发了Flask。Flask基于WerkzeugWSGI工具包和Jinja2模板引擎。两者都是Pocco项目。
Flask也被称为“microframework” ,因为它使用简单的核心,用extension增加其他功能。Flask没有默认使用的数据库、窗体验证工具。
目录结构上按照惯例, 模板和静态文件存放在应用的Python 源代码树的子目录中,名称分别为 templates 和 static 。
一个最基本的flask应用如下:
(注:摘自https://www.w3cschool.cn/flask/flask_application.html)
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello World’
if __name__ == '__main__':
app.run()
必须在项目中导入Flask模块。Flask类的一个对象是我们的WSGI应用程序。
Flask构造函数使用当前模块(__name __)的名称作为参数。
Flask类的route()函数是一个装饰器,它告诉应用程序哪个URL应该调用相关的函数。
app.route(rule, options)
· rule 参数表示与该函数的URL绑定。
· options 是要转发给基础Rule对象的参数列表。
在上面的示例中,'/ ' URL与hello_world()函数绑定。因此,当在浏览器中打开web服务器的主页时,将呈现该函数的输出。
最后,Flask类的run()方法在本地开发服务器上运行应用程序。
app.run(host, port, debug, options)
所有参数都是可选的
序号 | 参数与描述 |
1 | host 要监听的主机名。 默认为127.0.0.1(localhost)。设置为“0.0.0.0”以使服务器在外部可用 |
2 | port 默认值为5000 |
3 | debug 默认为false。 如果设置为true,则提供调试信息 |
4 | options 要转发到底层的Werkzeug服务器。 |
上面给出的Python脚本是从Python shell执行的。
Python Hello.py
Pythonshell中的消息通知您:
* Running on http://127.0.0.1:5000/(Press CTRL+C to quit)
在浏览器中打开上述URL(localhost:5000)。将显示“Hello World”消息。
2.2小米soar-web源码说明
其核心采用轻量级的web应用Flask框架编写,主要功能点《SQL评估》菜单涉及到的函数方法如下图所示。
前端web的SQL评估、美化、压缩、指纹、语法检查、SQL改写,在前端的URL为/soar-api ,转由后端soar-web.py的soar()方法实现。
其中decrypt()方法解密提交的post内容,采用AES对称加密算法对明文进行加密,然后把对称密钥使用RSA算法的公钥进行加密,传回给服务器,soar_args_check()为检查参数是否正确,检查通过之后,提交给soar_result()方法做SQL审核等操作。
加密方式为RSA非对称加密算法+AES对称加密的结合,生成公钥密钥的方法在初始化check_env()里面,代码如下:
其中check_env()方法中,介绍了如何创建密钥对。
RSA算法简介:1977年,三位数学家 Rivest、Shamir 和 Adleman 设计了一种算法,可以实现非对称加密。算法用他们三个人的名字命名,叫做RSA算法。
采用公钥加密的明文,只有私钥可以解密(用于客户端向服务端传数据的场景),使用私钥加密的明文,也只能采用公钥解密(用于数字证书的场景),这就是非对称加密。
AES算法简介:密码学中的高级加密标准(Advanced Encryption Standard,AES),又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。
至于为什么不直接使用RSA加密传送的data呢?因为非对称加密的公钥是对外公开的,如果服务器要回传data给客户端时,采用私钥加密data,那么其他用于公钥的人也能解密data,所以正常情况都是采用RSA非对称加密客户端生成的AES对称密钥,用这个AES对称密钥加密data,然后把RSA加密的密钥和密文传给服务器进行解密。
在python当中,可以直接安装Crypto模块,实现RSA和AES算法,解密的过程如下所示:
其中pkcs是公钥加密标准(Public Key Cryptography Standards, PKCS),此一标准的设计与发布皆由RSA信息安全公司所制定。源码用的标准是PKCS#1:定义RSA公开密钥算法加密和签名机制,主要用于组织PKCS#7中所描述的数字签名和数字信封。
因为加密的编码采用base64,所以解密这边对应的也是base64。
加密解密部分的源码介绍完,回到我们最初的SQL审核究竟是怎样实现的,直接使用soar的话,SQL审核命令格式为:
sh ./soar.linux-amd64 -config ./uuid.yaml-query 待评审SQL语句或SQL语句文件路径
soar_result()的功能就是将post的内容,校验合格之后,转换为可执行文件的命令行参数,提交给后台shell执行(通过python的subprocess模块),并将执行结果反馈给前端。
例如在页面提交的SQL语句为“select * from dual”,soar_result()就是将其转为./soar.linux-amd64-config ./uuid.yaml -query 'select * from dual',并通过subprocess.Popen在shell当中执行。
soar_result()源码如下:
其中soar_run_uuid生成临时文件的唯一路径,用于写入soar二进制程序的配置文件的参数、日志和黑名单,这些临时文件在soar_result()执行的最后删除掉。
req_parse2cmd_parse()将json参数转为一行可执行的命令行参数列表。
runcmd()为执行外部命令,该方法为:
这是通过python的subprocess这个模块来产生子进程,并连接到子进程的标准输入/输出/错误中去,还可以得到子进程的返回值。
subprocess.Popen参数如下:
本文用的参数说明
1.args参数:可以是一个字符串,可以是一个包含程序参数的列表。要执行的程序一般就是这个列表的第一项,或者是字符串本身。例如以下都可行:
subprocess.Popen(["cat","test.txt"])
subprocess.Popen("cattest.txt")
2.shell参数:如果把shell设置成True,指定的命令会在shell里解释执行,默认为False。
3.cwd参数:如果cwd不是None,则会把cwd做为子程序的当前目录。
4.stdinstdout和stderr,分别表示子程序的标准输入、标准输出和标准错误。可选的值有PIPE或者一个有效的文件描述符(其实是个正整数)或者一个文件对象,还有None。如果是PIPE,则表示需要创建一个新的管道,如果是None,不会做任何重定向工作,子进程的文件描述符会继承父进程的。另外,stderr的值还可以是STDOUT,表示子进程的标准错误也输出到标准输出。
5.universal_newlines参数:如果把universal_newlines 设置成True,则子进程的stdout和stderr被视为文本对象,并且不管是*nix的行结束符('/n'),还是老mac格式的行结束符('/r' ),还是windows 格式的行结束符('/r/n' )都将被视为 '/n' 。
2.3原版存在的小问题
原版对sql语句的长度是有限制的,因为是把sql语句直接提交在命令行参数里面。
所以在实际使用中,如果我们提交了超长的sql,那么就会报错,如下图所示。
原因是源码的调用命令行分析SQL语句的时候,是把SQL语句当作字符串处理,提交在命令行当中,例如:./soar.linux-amd64-config ./uuid.yaml -query 'select * from dual'。
解决方法是在执行命令行的时候,把sql语句写入到临时文件的方式进行审核。改为./soar.linux-amd64-config ./uuid.yaml -query SQL文件的路径。
改造如下:
初始源代码组合命令的方法中,是把SQL语句直接当中字符串写在“query”参数后面:
cmd_args['query'] = args['query']##源代码这里直接跟着SQL语句字符串。
我们先增加save_tmp_sqltext()函数方法,把post过来的sql语句写入临时文件。源码如下:
同时在soar_result()方法增加对SQL语句文件的处理,把获取到的SQL语句,调用save_tmp_sqltext()方法写入到临时文件当中,并把源码的query参数修改为SQL文件路径。
cmd_args['query'] = sqltext_tmp_file ##改造query后面的SQL语句为 SQL文件路径。
改造index.html关于post请求超时的处理,因为默认为30秒,当SQL语句比较长的时候,soar工具会花比较长的时间处理。
改造后的效果,SQL语句太长的报错已解决:
三、结论
soar web是一个采用轻量级web框架的应用,Flask类的route()函数处理前端URL对应到的后端方法,比较适合新手做二次开发。
![](https://oss-emcsprod-public.modb.pro/wechatSpider/modb_20211021_ddaebd72-325f-11ec-b086-fa163eb4f6be.png)