前言
我们目前开发的Oracle中间件目前主要的功能点是数据包转发、状态审计(客户端、SQL、表、事务等)、读写分离这些功能。其中审计功能中的SQL审计我们是基于SQL语句的特征码来进行审计的,例如审计SQL执行次数、耗费的时间、影响的行数、是否出现过错误等等这些指标。其中SQL语句中的值是没有参与审计的,现在我们做的就是加强这一块的审计,将SQL语句中所包含的值也参与审计,审计规则可以动态配置。
什么是SQL特征码
SQL特征码,就是一系列除了传入的参数值不一样的SQL的统一描述符。例如下面两条SQL语句:
SQL1:insert into table1 values (100, 'abc', '123')
SQL2:insert into table1 values (101, 'aaa', 'bbb')
它们的SQL特征码是一样的,经过中间件的SQL解析器进行处理后,可以替换成如下的SQL字符串:
insert into table1 values (?, ?, ?)
我们的审计正是基于这样的原理进行审计的。
SQL审计加强
加强SQL审计可以用一句话概括:SQL语句中的值也参与审计。
普通的查询完整的SQL语句我们是能够获取到的,在这里唯一的难点是带有绑定变量的查询,对于如上的insert查询,客户端代码是这样写的:
insert into table1 values (?, ?, ?),然后在调用函数去填充各个值,最后再调用执行过程。
实际上在网络协议传输中,是没法得到这个包含值的SQL字符串的。Oracle客户端会对这个用户传入的SQL字符串进行处理,会生成如下的形式的字符串,然后再发送到服务端,参数值并没有存放在SQL语句中。
这个是网络协议传输中的SQL字符串:insert into table1 values (:1, :2, :3)
对这样的SQL进行解析不是我们想要的,需要做的就是将绑定变量的值替换到原SQL中然后再进行审计。在这里你可能会产生这样的疑问:这样会不会很影响性能?这样做有什么好处?答:性能会有所影响,但不会很明显。好处是这是基于中间件的审计,不需要配置其他组件,对应用是透明的。这个可以参与内部SQL安全审计,该功能可以启用或者不启用。
题外话:据笔者所知,Oracle自身也带一些审计功能,细节之处没有逐一研究,但完整的SQL审计(包含带绑定变量的查询)目前没看到其他相关实现。
审计规则
目前审计规则是存放在程序启动的配置文件中的,例如我们现在有一个SQL语句正则表达式匹配的规则,可以这样配置:
其中 SQLRegex 是规则名,表示程序按正则表达式规则匹配SQL,后面的regex参数则为正则表达式字符串,这里我们只写了一个test,简单字符串匹配。现在写一个简单的java代码测试一下:
执行后程序输出:
从这张图可以看出,客户端传过来的SQL语句是不包含值的,后面可以看到程序替换后的SQL语句,并且该SQL是符合我们所定义的规则。
注:在这里只是功能的简单演示,目前还在继续完善中。有兴趣的可以关注下。