【连载】数据库审计产品常见缺陷(五)参数审计错误

参数绑定是数据库编程中常用的一种方法,通过这种方法,数据库系统可以减少编译次数,快速执行,提升效率;但这种编程方法将对数据库的审计带来挑战,在笔者所见到的若干数据库审计产品中,在这种情况下都出了不少的错误。有的是漏审了语句,有的是记录下了操作的语句,但将具体执行时所使用的参数记错了或漏记了。这些缺陷对于审计产品无疑很是致命。

为了详解这种情况,我们来看一下参数绑定的基本概念。我们在常规的图形化或命令行工具中,往往都是直接写上SQL语句,比如:

Select * from person_info where id=’12XXXXX6722’;

在这里查询条件是***号码。根据***号码查询个人信息,是一种常用功能,也是会重复使用的语句,为了提升效率,编程中可以这么写:

String sql1=’Select * from person_info where id=?;’

PreparedStatement pStmt = testConn.getConnection().prepareStatement(sql);

pStmt.setInt(1, ’12XXXXX6722’);

pStmt.execute();

下一次再使用时,就不用再发送语句了,可以直接发送:

pStmt.setInt(1, ’22XXXXX5399’);

pStmt.execute();

对于数据库审计系统而言,单纯地记录下来‘Select * from person_info where
id=?’是存在缺陷的,因为你无法明确额操作人员到底访问了哪个用户的信息,必须明确下来具体的参数才行。

这就要求将设定的参数,与Prepare的语句有效的关联,形成可视化的审计记录展现:

Select * from person_info where id=’12XXXXX6722’;

Select * from person_info where id=’22XXXXX5399’;

这实际上要求审计系统比起单纯的记录语句要完成更多的工作;其中一个重要任务的就是句柄追踪,本质上SQL语句的执行过程追踪就是句柄追踪过程。在上面显示的例子中

pStmt.execute(),在通讯过程中并不发送具体的语句,而仅是告知服务器要执行哪个语句句柄,服务器端会根据内部记录的句柄所对应的已经编译完成的SQL语句的执行计划,进行语句执行。数据库审计要完成相应的工作,需要执行类似的过程,在系统的内部也维护这样的映射关系;同时由于大多数数据库的句柄,是在会话级的,句柄是可重用的,因此在数据库审计中还要有效地维护句柄与session的关联,以及句柄的消亡。

在句柄维护之外,另一个有挑战的工作就是参数的还原。参数的还原,首要的是要明确参数所对应的句柄;在调用pStmt.setInt(1,
’22XXXXX5399’)时,在网络中发送的包,会标明这个参数是针对哪个句柄的,是针对第几个参数的。作为数据库审计产品,需要将参数与语句进行映射;更重要地要准确地填回参数所在的位置,上面这个例子由于只有一个参数,没有什么挑战性。但参数的绑定情况远比这个复杂,下面我们将提供一些例子来考验相关的数据库审计产品。

用例1:一个基本的示例

String sql = "select PID,NAME from PERFORMANCE_C t where pid=:1 and
balance>:2 and persionid>:3 and
datefield>TO_DATE(:4,‘YYYY-MM-DD‘)";

PreparedStatement  pStmt_2 =
testConn.getConnection().prepareStatement(sql);

pStmt_2.setInt(1, 84);

pStmt_2.setInt(2, 5555);

pStmt_2.setString(3, "120");

pStmt_2.setString(4, "1900-1-1");

pStmt_2.execute();

在这个示例中关键是看审计产品是否能将语句审计为:

select PID,NAME from PERFORMANCE_C t where pid=84 and balance>5555 and
persionid>‘120‘ and datefield>TO_DATE(‘1900-1-1‘,‘YYYY-MM-DD‘)

用例2:这是一个略有挑战的例子,但这个挑战已经有数据库审计产品无法将参数还原了

String sql = "select PID,NAME from PERFORMANCE_C t where pid=:pid and
balance>:balance and personid>:personid and
datefield>TO_DATE(:datefield,‘YYYY-MM-DD‘)";

PreparedStatement  pStmt_2 =
testConn.getConnection().prepareStatement(sql);

pStmt_2.setInt(1, 84);

pStmt_2.setInt(2, 5555);

pStmt_2.setString(3, "120");

pStmt_2.setString(4, "1900-1-1");

pStmt_2.execute();

这里的挑战在于参数并未使用常规的‘?’号或者‘:1’,这样的方式,而是采用了字符串的方式;验证的答案依然是:

select PID,NAME from PERFORMANCE_C t where pid=84 and balance>5555 and
personid>‘120‘ and datefield>TO_DATE(‘1900-1-1‘,‘YYYY-MM-DD‘)

用例3:这个挑战同样有数据库审计产品出错了

String sql = "select PID,NAME from PERFORMANCE_C t where personid>:1 and
pid=:2 and balance>:3 and personid< 32 + :1;

PreparedStatement pStmt_2 =
testConn.getConnection().prepareStatement(sql);

pStmt_2.setInt(1, "120");

pStmt_2.setInt(2, 84);

pStmt_2.setInt(3, 5555);

pStmt_2.setInt(4,84);

pStmt_2.execute();

这里的挑战在于参数1和参数4用的是同参数编号;验证的答案是:
select PID,NAME from PERFORMANCE_C t where
personid>120 and pid=84 and balance>5555 and personid < 32 + 120;

用例4:若单纯地采用’:’进行分割的参数还原肯定会出错

String sql = "select PID,NAME from PERFORMANCE_C t where pid>:1 and
personid =:2 and content like ‘Name:3%’ and balance>:3";

PreparedStatement  pStmt_2 =
testConn.getConnection().prepareStatement(sql);

pStmt_2.setInt(1, 84);

pStmt_2.setString (2, "120");

pStmt_2.setString (3, 5555);

pStmt_2.execute();

验证的答案是:

select PID,NAME from PERFORMANCE_C t where personid>120 and pid=84 and 
content like ‘’Name:3%’ and balance>5555;

用例5:这个挑战是验证对于多prepared语句下是否能准确地将执行的语句和对应的参数都审计下来,这里我们将提供两条语句进行交互的执行:

public void TestCase_PrepareSelect_3()

{

String sql_1 = "select pid,balance,account from F10_USER t where
pid=:pid";

//String sql_2 = "select NAME,PID,balance from PERFORMANCE_C t
where pid=:1 and

balance>:2 and persionid>:3 and
datefield>TO_DATE(:4,‘YYYY-MM-DD‘)";

String sql_2 = "select NAME,PID,balance from F10_USER t where
pid=:1 andbalance>:3 and persionid>:2 and
datefield>TO_DATE(:4,‘YYYY-MM-DD‘)";

try {

pStmt = testConn.getConnection().prepareStatement(sql_1);

pStmt_2 = testConn.getConnection().prepareStatement(sql_2);

//第一轮执行

pStmt_2.setInt(1, 94);

pStmt_2.setInt(2, 5555);

pStmt_2.setString(3, "120");

pStmt_2.setString(4, "1900-1-1");

pStmt_2.execute();

testRest_2 = pStmt_2.getResultSet();

while(testRest_2.next())

{

pid = testRest_2.getInt("PID");

System.out.println("PID="+pid);

}

pStmt.setInt(1, 84);

pStmt.execute();

testRest = pStmt.getResultSet();

while(testRest.next())

{

pid = testRest.getInt("PID");

System.out.println("PID="+pid);

}

//第2轮执行

pStmt.setInt(1, 85);

pStmt.execute();

testRest = pStmt.getResultSet();

while(testRest.next())

{

pid = testRest.getInt("PID");

System.out.println("PID="+pid);

}

pStmt_2.setInt(1, 95);

pStmt_2.setInt(2, 1555);

pStmt_2.setString(3, "1305");

pStmt_2.setString(4, "1920-1-1");

pStmt_2.execute();

testRest_2 = pStmt_2.getResultSet();

while(testRest_2.next())

{

pid = testRest_2.getInt("PID");

System.out.println("PID="+pid);

}

//第3轮执行

pStmt_2.setInt(1, 96);

pStmt_2.setInt(2, 5123);

pStmt_2.setString(3, "1201");

pStmt_2.setString(4, "1930-1-1");

pStmt_2.execute();

testRest_2 = pStmt_2.getResultSet();

while(testRest_2.next())

{

pid = testRest_2.getInt("PID");

System.out.println("PID="+pid);

}

pStmt.setInt(1, 86);

pStmt.execute();

testRest = pStmt.getResultSet();

while(testRest.next())

{

pid = testRest.getInt("PID");

System.out.println("PID="+pid);

}

//         testRest.close();

//         pStmt.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

应该来讲,这是一个并不复杂的多语句执行示例,但某知名厂商的数据库审计产品,将sql_1被审计到了4次,sql_2被审计到了1次。这仅仅是一种简单的多语句执行情况,我们现实中的应用要更为复杂。

大家可以访问这个链接,该链接将提供更为一个完整的参数绑定示例;我们可以测测所使用的数据库审计产品能否准确审计:http://www.dbsec.cn/a/shujukuanquan/shujukufanghushouduan/shujukushenj/index.html

下面我们不再对这些简单的情况进行讨论,我们将讨论一种更为复杂的参数绑定情况,也就是批量参数绑定。

批量参数绑定是DBMS提供商为了提供更为高效的数据操作速度,而提供的一批参数发送,语句多次执行;该方式通过更少的网络通讯次数、更少的SQL层的语境切换等大幅度提高编程效率。这种执行方式在一般的编程中很少使用,但在类似于电信运营商的计费系统这样的环境,对性能的要求很高,往往需要每秒接近上万条的插入或更新,则是一种较为常见的使用方式;因此对于运行商、证券金融、互联网这样的瞬时交易量非常大,需要采用最为高效的数据处理方式的应用环境需要对这种参数绑定方式兼容。

下面是一个批量插入的示例,仅仅是为了检验审计产品是否支持该功能:
PreparedStatement statement =
connection.prepareStatement("INSERT INTO Tbl1 VALUES(?,
?)");
//记录1
statement.setInt(1, 1);
statement.setString(2,
"Cujo");
statement.addBatch();

//记录2
statement.setInt(1,
2);
statement.setString(2,
"Fred");
statement.addBatch();

//记录3
statement.setInt(1,
3);
statement.setString(2,
"Mark");
statement.addBatch();

//批量执行上面3条语句.
int [] counts =
statement.executeBatch();

现在我们需要考察所使用的数据库审计产品,能否准确地审计下3条插入语句并且每条语句都能准确地匹配上相应的参数;或者审计为1条插入语句,3组参数。

这只是批量插入中一个轻微的挑战,更为复杂的是当批量更为大情况,Oracle和SQL
Server这样的考虑更为精细的产品,会对数据采用压缩的处理方式,比如对重复值的表达,对Null值的表达等;数据库审计产品是否能有效地还原每个批量成员的值,将会是一个挑战。

当前我们所见到的绝大多数数据库审计产品在批量参数绑定的执行语句的情况下,都无法准确审计下批量查询中所执行的语句和对应的参数。

时间: 2024-11-08 11:53:32

【连载】数据库审计产品常见缺陷(五)参数审计错误的相关文章

【连载】数据库审计产品常见缺陷(4)数据库对象解析错误

继上期为大家介绍了有关数据库审计多语句无法有效分割的问题,本期,安华金和围绕数据库对象解析错误分析数据库审计产品常见缺陷.数据库审计产品中一个重要需求是要有效记录下来SQL语句的操作类型.访问对象:根据这些操作类型和访问对象,审计产品可以有效地制订告警策略,可以有效地根据操作类型.访问对象进行事后的追踪与检索.我国相关部门的数据库审计产品标准中要求:应对数据库网络访问对象的名称进行准确审计,包括数据库服务器名称.IP名称.数据库名称.表.视图.序列.包.存储过程.函数.库.索引和触发器等. 目前

【连载】数据库审计产品常见缺陷(3)多语句无法有效分割

继上期为大家介绍了有关数据库审计产品长SQL语句漏审的问题,本期,安华金和围绕多语句的有效分割分析数据库审计产品常见缺陷.多语句是SQL Server上的一个特定情况.在其它的数据库管理系统中,语句之间都有明确的分割标识:而在SQL Serve中语句之间可以没有明确的分隔符.下面是一个示例: use opencms SET NOCOUNT ON select * fromopencms.opencms.CMS_LOG where 1=1 or 'a' ='b' select * fromopen

【连载】数据库审计产品常见缺陷(1)-综述

随着信息化的发展,数据库安全问题成为当前政府和企业用户关注的焦点,数据库审计产品成为当前信息安全产品的新宠. 当前在市面上存在着几十种数据库审计产品,这些产品的来源大约有四种类型: 国内原先具有网络审计产品的厂商,在网络审计产品的基础上经过简单包装,推出的数据库审计产品,比如我国几大安全厂商推出的数据库审计产品: 国内厂商专门针对数据库通讯协议的特点,开发出专门的数据库审计产品,比如安华金和.思福迪.安恒.国都兴业和帕拉迪等: 国外的数据库审计产品,比如Imperva.Guardium等: OE

数据库基础(面试常见题)

一.数据库基础 1. 数据抽象:物理抽象.概念抽象.视图级抽象,内模式.模式.外模式 2. SQL语言包括数据定义.数据操纵(Data Manipulation),数据控制(Data Control) 数据定义:Create Table,Alter Table,Drop Table, Craete/Drop Index等 数据操纵:Select ,insert,update,delete, 数据控制:grant,revoke 3. SQL常用命令: CREATE TABLE Student( I

js 跨域问题常见的五种解决方式

一.什么是跨域? 要理解跨域问题,就先理解好概念.跨域问题是由于javascript语言安全限制中的同源策略造成的. 简单来说,同源策略是指一段脚本只能读取来自同一来源的窗口和文档的属性,这里的同一来源指的是主机名.协议和端口号的组合. URL 说明 是否允许通信 http://www.a.com/a.js http://www.a.com/b.js 同一域名下 允许 http://www.a.com/lab/a.js http://www.a.com/script/b.js 同一域名下不同文件

authentication-mode 常见的配置参数有三种

authentication-mode 常见的配置参数有三种user-interface vty 0 14 1.authentication-mode aaa或authentication-mode    scheme创建本地用户并启用AAA验证. 2.authentication-mode password 直接在user-interface vty 下用passrod设置密码 3.authentication-mode none远程维护登陆不需要密码 scheme是组合的意思.就是组合认证方

铝合金阳极氧化的常见缺陷

外观缺陷是造成型材返工从而大幅度提高成本的主要原因.本文综述铝阳极氧化膜外观缺陷的主要特征,成因和对策.按照外观形态,可将阳极氧化表面缺陷分为三大类:(1)条纹(带)状缺陷;(2)斑点状缺陷;(3)不均匀(不正常)表面.由于条纹(带)状缺陷往往起因于熔铸和挤压,或其它机械损伤,本文只介绍后两类常见缺陷. 1 斑点状缺陷材料腐蚀.槽液污染.合金第二相析出或电偶作用等因素均可导致斑点状缺陷,分别介绍如下: 1.1 酸或碱浸蚀在阳极氧化前,由于铝材溅上酸液或碱液或者受到酸雾或碱雾作用而腐蚀,使表面局部

纠正要求修改数据库NLS_LENGTH_SEMANTICS参数的错误要求

1.开发人员错误的要求 先看一封开发人员向某DBA提出的一个"要求修改数据库NLS_LENGTH_SEMANTICS参数"的邮件: 上面邮件,出于对隐私的保护,对发件人,收件人,数据库名称进行了隐涂. 邮件内容主要意思是: (1)   源端和目标端数据库的字符集均为SIMPLIFIED CHINESE_CHINA.UTF8,但是源端数据库NLS_LENGTH_SEMANTICS参数的值为char,目标数据库NLS_LENGTH_SEMANTICS参数的值为byte (2)   邮件中对

log4j常见的五个等级

1.级别说明 级别顺序(低到高): DEBUG < INFO < WARN < ERROR < FATAL 2.测试实例 /** * @Title:LogLevel.java * @Package:com.you.log * @Description:log4j日志等级 * @Author: 游海东 * @date: 2014年7月8日 下午10:58:41 * @Version V1.2.3 */ package com.you.log; import org.apache.lo