数据库审计产品常见缺陷之(三)多语句无法有效分割-k8凯发天生赢家

数据库审计产品常见缺陷之(三)多语句无法有效分割
作者:刘晓韬 发布时间:2016-08-16

继上期为大家介绍了有关数据库审计产品长sql语句漏审的问题,本期,安华金和围绕多语句的有效分割分析数据库审计产品常见缺陷。多语句是sql server上的一个特定情况。在其它的数据库管理系统中,语句之间都有明确的分割标识;而在sql serve中语句之间可以没有明确的分隔符。下面是一个示例:

use opencms set nocount on select * from opencms.opencms.cms_log where 1=1 or ‘a’ =’b’ select * from opencms.opencms.cms_history_projects where 1=1

在这些语句之间没有类似于 ;号这样的明确分隔标识符;它们实际代表了四条语句:

use opencms

set nocount on

select * from opencms.opencms.cms_log where 1=1 or ‘a’ =’b’

select * from opencms.opencms.cms_history_projects where 1=1

sql server会将这些语句不加分割地组织在一个数据库通讯包中发送;对于一些专业化程度不高的数据库审计产品,会将这些语句作为一条语句审计下来。有效地实现多语句分割,需要非常专业的sql解析技术。一些简单的方法,比如用select、use 、set这样的关键字来进行语句分割,稍微复杂的情况就不好处理了;下面这个示例,就无法用这种简单的方法处理:

select * from t1 where t1.col1 = 1 union select * from  t2 where t2.col1 = 1 select * from t2 where t2.col1 = 1

即使采用稍微复杂一些的技术,比如正则表达式,也很难做到准确切割;非专业化的数据库审计产品都存在这个缺陷。 对无法准确切割多语句的缺陷,在不同的产品中表现不同,所造成的审计问题也不同,但大体可以总结为如下几点:

(1)在审计记录中,不能准确记录下每条语句的sql操作类型,从而造成一些高危操作不能有效地被识别或告警,比如drop、truncate这些语句。

(2)在审计记录中,不能准确记录下每条sql语句的数据库对象,从而造成对敏感对象的访问不能有效地被识别或告警。

(3)在审计记录中,不能准确地记录每条语句是否执行成功;比如多条语句中第一条语句执行成功,后面的语句执行失败了,往往会被整体记录为一个结果,往往记录的结果是成功。

(4)在审计记录中,不能准确地反馈出每条语句造成的影响行数,从而也无法触发基于影响行的安全策略;往往记录下来的都是第一条语句的影响行,其余语句的影响行都被忽略掉了。

下面的结果是安华金和专业的数据库审计产品的执行结果,该产品准确实现了多语句切割,同时准确审计了每条语句的执行成功与否和影响行:

以上结果,根据语句发送的先后顺序进行了倒排显示,同时审计了每条语句的操作对象、sql语句、执行成功与否,影响行数。

安华金和的数据库审计专家准备了一些用例,来帮助读者验证数据库审计产品能否完成多语句切割,是否准确地审计了每条语句的访问对象、返回结果和影响行:

用例一(一个很基本的多语句例子)

insert into #am_dbfileio(collection_time,total_io_bytes)values(@current_collection_time,@current_total_io_mb)

insert #t1 ( object_id, object_type, rank)

select t.relative_id, t.relative_type, 1 from #t1 t where t.relative_id not in ( select t2.object_id from #t1 t2 where not t2.object_id is null )

用例二(一个稍显复杂点的,与游标相关的多语句示例):

declare tables_cursor cursor

for

select name from sysobjects where type = 'u'

open tables_cursor

declare @tablename sysname

fetch next from tables_cursor into @tablename

while (@@fetch_status <> -1)

begin

/* a @@fetch_status of -2 means that the row has been deleted.

there is no need to test for this because this loop drops all user-defined tables. */

exec ('drop table ' @tablename)

fetch next from tables_cursor into @tablename

end

print 'all user-defined tables have been dropped from the database.'

deallocate tables_cursor ;

用例三:(一个更复杂的的多语句示例)

set nocount on;

-- check agent status

create table #tempagentstatus (agentstatus nvarchar(50))

if (is_srvrolemember('sysadmin') > 0)

insert #tempagentstatus (agentstatus)

exec master..xp_servicecontrol n'querystate',n'sqlserveragent' ;

else

insert #tempagentstatus (agentstatus) -- sometimes this check doesn't work - there are complains on the www

select 'running' from master.dbo.sysprocesses where program_name like n'sqlagent%generic%refresher%'

declare @agentrunning int;

set @agentrunning = 0

select @agentrunning =1 from #tempagentstatus where charindex(n'running', lower(agentstatus)) > 0

drop table #tempagentstatus

-- end check agent status

declare @can_see_all_running_jobs int;

set @can_see_all_running_jobs = isnull(is_srvrolemember(n'sysadmin'), 0);

declare @current_execution_status int;

declare @job_owner sysname;

set @job_owner = suser_sname();

create table #xp_results

(

job_id uniqueidentifier not null,

last_run_date int not null,

last_run_time int not null,

next_run_date int not null,

next_run_time int not null,

next_run_schedule_id int not null,

requested_to_run int not null, -- bool

request_source int not null,

request_source_id sysname collate database_default null,

running int not null, -- bool

current_step int not null,

current_retry_attempt int not null,

job_state int not null

);

if @agentrunning = 1

begin

insert into #xp_results

execute master.dbo.xp_sqlagent_enum_jobs @can_see_all_running_jobs, @job_owner;

end

select distinct

count(1)

from

msdb.dbo.sysjobs_view obj left outer join msdb.dbo.sysjobservers js on js.job_id = obj.job_id

left outer join msdb.dbo.sysjobhistory jh on (jh.job_id = obj.job_id) and

(jh.step_id = 0) and

(jh.instance_id = (select max(ijh.instance_id)

from msdb.dbo.sysjobhistory ijh

where ijh.job_id = obj.job_id))

left outer join #xp_results res on js.job_id = res.job_id

drop table #xp_results;


网站地图