继上期为大家介绍了有关数据库审计多语句无法有效分割的问题,本期,安华金和围绕数据库对象解析错误分析数据库审计产品常见缺陷。数据库审计产品中一个重要需求是要有效记录下来sql语句的操作类型、访问对象;根据这些操作类型和访问对象,审计产品可以有效地制订告警策略,可以有效地根据操作类型、访问对象进行事后的追踪与检索。我国相关部门的数据库审计产品标准中要求:应对数据库网络访问对象的名称进行准确审计,包括数据库服务器名称、ip名称、数据库名称、表、视图、序列、包、存储过程、函数、库、索引和触发器等。
目前国内大多数数据库审计产品都会宣称支持对sql语句操作类型和访问对象的审计支持;但事实上,很多审计产品的支持能力有限,往往只能支持一些简单语句的解析,比如这样的语句:
select * from tbl1 where col1 > ’1’;
但笔者曾经见过一家大型的信息安全厂商的产品,仅仅是在表名前增加一个schema名称,就发生了令人震惊的错误;这个产品居然将schema名称审计为了表名。如上面这条语句改为;
select * from user1.tbl1 where col1 > ‘1’;
这种数据库审计产品就会将user1记录为表名。
出现这种情况说明产品设计的比较粗糙,还远远达不到专业的数据库审计产品的要求;这通常是一些网络审计产品厂商,未经过严肃的产品开发过程,仅对原有的网络审计产品进行了简单包装就推向了市场;这些厂商依靠已经积累的品牌和用户的信任,提供了不严肃的数据库审计产品。而国家相关部门在产品的认证过程中以及用户的演示中,并未真正仔细地对此进行测试。
事实上,上面被误报的例子,是一个非常简单的例子,大多数专业的数据库审计产品都不会犯这样的错误。事实上,真正的挑战要比上面的例子复杂很多。安华金和的数据库审计专家为读者准备了一些示例,读者可以验证下所使用的数据库审计产品是否支持对这些类型的语句的操作类型和访问对象的正确解析。下面的示例,若是未明确说明数据库类型,那么均可在oracle上执行通过。
示例1:
select * from user1.tbl1 where col1 > ‘1’;
挑战:
是否准确识别出表名是tbl1,数据库名称是user1;
示例2:以下语句在sql server上可运行
select [name],
[salesamount]
from [adventureworks].[production].[product] p
挑战:
是否准确识别出表名是product,数据库名称是adventureworks,schema名称是production;
如:
select col1, col2 from tbl1
union
select col1,col2 from tbl2
union
select mycol1,mycol2 from tbl3
union
select col3,col4 from tbl1;
挑战:
是否准确识别出表是tbl1、tbl2、tbl3
示例1:oracle上的多表更新语句:
update landleveldata a set (a.gqdltks, a.bztks)= (select b.gqdltks, b.bztks from gdqlpj b where a.geo_code=b.lxqdm)
挑战:
是否准确识别出涉及的表包括landleveldata、gdqlpj
示例2:sql server上的多表更新语句:
update a set a.gqdltks=b.gqdltks,a.bztks=b.bztks from landleveldata a,gdqlpj b where a.geo_code=b.lxqdm
挑战:
是否准确识别出涉及的表包括landleveldata、gdqlpj
示例3:mysql上的多表更新语句:
update landleveldata a, gdqlpj b set a.gqdltks= b.gqdltks, a.bztks= b.bztks where a.geo_code=b.lxqdm
挑战:
是否准确识别出涉及的表包括landleveldata、gdqlpj
insert语句有两种句式涉及多表:insert into .... select....
select ....into [table] from
示例1:
insert into tbl1(col1,col2,col3) select col1,col2,col3 from tbl2 where tbl2.col1=’new’;
挑战:识别出tbl1和tbl2;
示例2:以下语句在sql server上可运行
select col1,col2,col3 into tbl1 from tbl2 where tbl2.col1=’new’;
挑战:识别出tbl1和tbl2;
join是多表关联查询的基础,形式也更多样;挑战也更巨大:
示例1:简单join语句
select t1.a,t2.b from t1, t2 where t1.c=t2.c
挑战:
将表t1和t2均识别出来
示例2:inner join的语句
select t1.a,t2.b from t1 inner join t2 on t1.c=t2.c
left join t3 on t1.c=t3.c where t1.name like ‘刘%’ and prince = ‘北京’;
挑战:
将t1、t2、t3表都准确地识别出来。
示例3:一个更为复杂的join情况,该语句是在sql server中执行的,由开放应用软件opencms实际发出的,以下语句在sql server上可运行:
select clmns.column_id as [id],clmns.name as [name],clmns.is_nullable as [nullable],
cast(isnull(cik.index_column_id,0)as bit)as [inprimarykey],clmns.is_identity as [identity],usrt.name as [datatype],
isnull(baset.name,n'')as [systemtype],cast(case when baset.name in(n'nchar',n'nvarchar')and clmns.max_length<>-1
then clmns.max_length/2 else clmns.max_length end as int)as [length],cast(clmns.precision as int)as
[numericprecision],cast(clmns.scale as int)as [numericscale],isnull(xscclmns.name,n'')as [xmlschemanamespace],
isnull(s2clmns.name,n'')as [xmlschemanamespaceschema],
isnull((case clmns.is_xml_document when 1 then 2 else 1 end),0)as [xmldocumentconstraint],sclmns.name as [datatypeschema]
from sys.tables as tbl
inner join
sys.all_columns as clmns on clmns.object_id=tbl.object_id left
outer join
sys.indexes as ik on ik.object_id=clmns.object_id and 1=ik.is_primary_key left
outer join
sys.index_columns as cik on cik.index_id=ik.index_id and cik.column_id=clmns.column_id and cik.object_id=clmns.object_id and 0=cik.is_included_column
left outer join
sys.types as usrt on usrt.user_type_id=clmns.user_type_id
left outer join
sys.types as baset on(baset.user_type_id=clmns.system_type_id and baset.user_type_id=baset.system_type_id)or((baset.system_type_id=clmns.system_type_id)
and(baset.user_type_id=clmns.user_type_id)and(baset.is_user_defined=0)and(baset.is_assembly_type=1))
left outer join
sys.xml_schema_collections as xscclmns on xscclmns.xml_collection_id=clmns.xml_collection_id
left outer join
sys.schemas as s2clmns on s2clmns.schema_id=xscclmns.schema_id
left outer join
sys.schemas as sclmns on sclmns.schema_id=usrt.schema_id
where(tbl.name='cms_history_projects' and schema_name(tbl.schema_id)='opencms')order by [id] asc
挑战:
将表名:[sys].[all_columns]; [sys].[indexes]; [sys].[index_columns]; [sys].[schemas]; [sys].[tables]; [sys].[types]; [sys].[xml_schema_collections]都识别出来。
子查询是另外一种复杂的情况,整个sql语句中的表并未老老实实地呆在from语句和where语句之间,而是渗透到了语句中,这个时候我们要是审计到所有的表对象,将有更大的挑战。
示例1:一个简单的子查询语句
select * from tbl1 where tbl1.col1 in (select col1 from tbl2 where col2=’中国’);
挑战:
识别出表tbl1和tbl2
示例2:在join中的子查询
select p.productid, p.name, p.productnumber, m.name as productmodelname
from production.product p inner join
(select name, productmodelid
from production.productmodel) m
on p.productmodelid = m.productmodelid
挑战:
识别出表production.product和production.productmodel
示例3:作为计算列的子查询,以下语句在sql server上可运行
select [name],
(select count(*) from adventureworks.sales.salesorderdetail s
where s.productid=p.productid) as salesamount
from [adventureworks].[production].[product] p
挑战:
识别出表adventureworks.sales.salesorderdetail和[adventureworks].[production].[product]
毫无疑问,下面这个示例将是所有基于正则表达等方式进行匹配分析的数据库审计产品的噩梦;这里融合了多种sql复杂的语法特征,只有基于yacc/lex这样的词法和语法分析技术的专业数据库审计产品才能胜任;这条语句来源于opencms开放应用,该语句在sqlserver中可执行:
insert #t1 (object_id, object_type, relative_id, relative_type, rank)
select distinct
case when 77 = t.relative_type then obj2.parent_object_id else t.relative_id end, -- object_id
case when 77 = t.relative_type then 1 else relative_type end, -- object_type
dp.referenced_major_id, -- relative_id
case -- relative_type
when dp.class < 2 then
case when 'u' = obj.type then 1
when 'v' = obj.type then 2
when 'tr' = obj.type then 3
when 'af' = obj.type then 4
when obj.type in ( 'p', 'rf', 'pc' ) then 5
when obj.type in ( 'tf', 'fn', 'if', 'fs', 'ft' ) then 6
when exists (select * from sys.synonyms syn where syn.object_id = dp.referenced_major_id ) then 7
end
when dp.class = 2 then (case
when exists (select * from sys.assembly_types sat where sat.user_type_id = dp.referenced_major_id) then 8
else 9
end)
end,
3
from #t1 as t
join sys.sql_dependencies as dp on
-- reference table, view procedure
( class < 2 and dp.object_id = t.relative_id and t.relative_type in ( 1, 2, 3, 4, 5, 6, 77) )
--reference type
or ( 2 = class and dp.object_id = t.relative_id ) -- t.relative_type?
--reference xml namespace ( not supported by server right now )
--or ( 3 = class and dp.referenced_major_id = t.relative_id and 10 = t.relative_type )
left join sys.objects as obj on obj.object_id = dp.referenced_major_id and dp.class < 2 and obj.type in ( 'u', 'v', 'p', 'rf', 'pc', 'tf', 'fn', 'if', 'fs', 'ft', 'tr', 'af')
left join sys.objects as obj2 on obj2.object_id = t.relative_id and 77 = t.relative_type
where 3 = t.rank
挑战:
能够完全识别出访问的数据库表包括:#t1、sys.synonyms、sys.assembly_types、sys.sql_dependencies、sys.objects
试用申请