SQL Server DDL安全审计

应用场景:

        作为SQL Server安全审计的一部分,DBA可能需要这样的一份报吿:知道哪些数据库对象(储如表、存储过程、视图、用户、函数、用户权限等等)在什么时候被谁修改过,以及修改的内容等等。也还可能需要一份存储过程、函数以及视图的代码修改历史清单,知道这些代码在去过某段时间里被修改。那么,下面这份代码正好是你所需要的。

        此代码在SQL Server 2005/2008运行良好。


1.      建立一个审计数据库,专门用于存放审计记录;

此步骤略。审计数据库名为:AuditDB;

 

2.      建立一个审计用户,用于实施审计时所需要的权限;

[html]  view plain copy
  1. CREATE LOGIN[AuditUser]WITH PASSWORD=N'123',DEFAULT_DATABASE=[AuditDB]  
  2. GO  
  3. use AuditDB  
  4. GO  
  5. CREATE USERAudituserFOR LOGIN Audituser;  
  6. GO  
  7. ALTER LOGIN[AuditUser]DISABLE  
  8. GO  

注:该用户无需登录,所以可以禁用此用户的登录。


3.      在审计数据库AuditDB上建立下如下审计表:

表1:DBA_ChangedObjectLog(审计主表)


表2:DBA_ChangedObjectText(审计从表) 


注: 

审计主表与审计从表之间的关联字段是LogID;

只有视图、存储过程、函数、触发器才有从表数据,因为只有这些对象才有代码定义;

 

4.      为审计用户AuditUser授权:

[sql]  view plain copy
  1. use master  
  2. go  
  3. grant viewserverstate to Audituser  
  4.   
  5. use AuditDB  
  6. go  
  7. grant insertonDBA_ChangedObjectLogtoAudituser  
  8. grant insertonDBA_ChangedObjectTexttoAudituser  


5.      为所有可以修改数据库对象的用户,授予模拟AuditUser的权限:

如果你不这么做,那你就必须为所有这些用户分别授予第四步中AuditUser的权限;

[sql]  view plain copy
  1. grant impersonateonlogin::user1toaudituser  
  2. grant impersonateonlogin::auditusertouser1  

如果你的数据库中已经有几十上百或上千的用户,那你可以用如下语句生成的代码批量授权:

[sql]  view plain copy
  1. select 'grant impersonate on login::['+[name]+'] to audituser'fromsys.server_principals  
  2. where type='S'andname<>'audituser'  
  3. union all  
  4. select 'grant impersonate onlogin::audituser to ['+[name]+']'fromsys.server_principals  
  5. where type='S'andname<>'audituser'  

注:以对后新建的每个用户,也必须这样授权。

 

6.      在审计主表上建立触发器tr_Dba_ObjectChangeLog_insert

此触发器的目的是获得当前修改的数据库对象(视图、存储过程、函数、触发器)代码定义并保存入从表中。

[sql]  view plain copy
  1. USE [AuditDB]  
  2. GO  
  3. SET ANSI_NULLSON  
  4. GO  
  5. SET QUOTED_IDENTIFIERON  
  6. GO  
  7.    
  8. --在审计主表上建立触发器:  
  9. ALTER trigger[dbo].[tr_Dba_ObjectChangeLog_insert]  
  10. on [dbo].[DBA_ChangedObjectLog]  
  11. for insert  
  12. as  
  13. begin  
  14.     declare  
  15.        @Logid uniqueidentifier,  
  16.        @DatabaseNamenvarchar(256),  
  17.        @UserNamenvarchar(256),  
  18.        @SchemaNamenvarchar(256),  
  19.        @ObjectNamenvarchar(256),  
  20.        @ObjectTypenvarchar(256),  
  21.        --@original_usernvarchar(256),  
  22.        @EventTypenvarchar(256),  
  23.        @sql nvarchar(256),  
  24.        @IsaDDLTriggerint  
  25.    
  26.        execute as login =original_login()  
  27.    
  28.        set @IsaDDLTrigger= -1  
  29.        select @Logid=logid,@DatabaseName=DatabaseName,@SchemaName=SchemaName,@ObjectName=ObjectName,@ObjectType=ObjectType,@UserName=UserName,@EventType=EventType  
  30.        from inserted;  
  31.    
  32.        if  @ObjectType not in('PROCEDURE','VIEW','FUNCTION','TRIGGER'return;  
  33.        if @EventType like 'DROP%'return;  
  34.    
  35.        set @sql = N'select @IsaDDLTriggerOut=count(*) from ['+@DatabaseName+'].sys.triggers where name='''+@ObjectName+''' and parent_class=0';  
  36.        execute sp_executesql@sql,N'@IsaDDLTriggerOut int OUTPUT',@IsaDDLTriggerOut=@IsaDDLTriggerOUTPUT;  
  37.    
  38.        --DDL触发器不能使用sp_helptext获得它的文本  
  39.        if @IsaDDLTrigger>0 return;      
  40.    
  41.        if object_id('tempdb..#temp')isnot null  
  42.            drop table #temp  
  43.    
  44.        create table #temp(  
  45.            [Line][int]IDENTITY(1,1)NOTNULL,  
  46.            [LineText]varchar(max)  
  47.        )  
  48.    
  49.        set @sql='insert into #temp exec ['+@DatabaseName+'].dbo.sp_helptext '''+@SchemaName+'.'+@ObjectName+'''';  
  50.        exec (@sql)  
  51.      
  52.        execute as caller  
  53.        insert into dbo.Dba_ChangedObjectText  
  54.        select @Logid,@DatabaseName,@SchemaName,@ObjectName,[Line],[LineText]from#temp  
  55.    
  56.        drop table #temp   
  57. end  


7.      在要实施审计的数据库上建立触发器tr_dba_Trace_ObjectChangeLog

建立之前,需要对要实施审计的数据库如下配置。例如你需要对数据库TEST进行DDL审计,则:

[sql]  view plain copy
  1. alter database[TEST]set trustworthy on  

然后再建立触发器tr_dba_Trace_ObjectChangeLog

[sql]  view plain copy
  1. USE [TEST]  
  2. GO  
  3. SET ANSI_NULLSON  
  4. GO  
  5. SET QUOTED_IDENTIFIERON  
  6. GO  
  7.   
  8. CREATE trigger[tr_dba_Trace_ObjectChangeLog]  
  9. on database  
  10. --withexecute as 'AuditUser'  
  11. for ddl_table_events,ddl_view_events,ddl_index_events,  
  12.     ddl_synonym_events,ddl_function_events,ddl_procedure_events,ddl_trigger_events,   
  13.     ddl_database_security_events--,ddl_rule_events    
  14. as  
  15. begin  
  16.     set nocount on  
  17.    
  18.     declare  
  19.        @newid UNIQUEIDENTIFIER,   
  20.        @data xml,  
  21.        @spid smallint,  
  22.        @LoginNamevarchar(256),  
  23.        @ProgramNamevarchar(256),  
  24.        @IP varchar(15),  
  25.        @mac varchar(12),  
  26.        @EventTypevarchar(50),  
  27.        @ObjectTypevarchar(25),  
  28.        @ObjectNamevarchar(256),  
  29.        @IsaDDLTriggerint,  
  30.        @Line smallint  
  31.    
  32.     set @newid = newid()  
  33.     set @data = EVENTDATA()  
  34.     set @spid = @data.value('(/EVENT_INSTANCE/SPID)[1]','smallint')  
  35.     set @EventType = @data.value('(/EVENT_INSTANCE/EventType)[1]','varchar(50)')  
  36.     set @ObjectType = @data.value('(/EVENT_INSTANCE/ObjectType)[1]','varchar(25)')  
  37.     set @ObjectName = @data.value('(/EVENT_INSTANCE/ObjectName)[1]','varchar(256)')  
  38.     set @LoginName = @data.value('(/EVENT_INSTANCE/LoginName)[1]','varchar(256)')  
  39.     --set @ObjectName= @data.value('(/EVENT_INSTANCE/ObjectName)[1]', 'varchar(256)')  
  40.     set @mac =(SELECTNET_ADDRESSFROM master.dbo.sysprocessesWHEREspid = @spid)  
  41.     set @Line = 0  
  42.    
  43.     --过滤掉由维护计划生成的重建索引记录(因此类记录太庞大)  
  44.     if @LoginName='NT AUTHORITY\SYSTEM'and@ObjectType= 'INDEX'  
  45.        return;  
  46.    
  47.     -- if the objectis a ddl trigger  
  48.     if (selectcount(*)from sys.triggerswherename=@ObjectNameandparent_class=0)= 0  
  49.        set @IsaDDLTrigger = 0  
  50.     else set @IsaDDLTrigger = 1  
  51.    
  52.     execute as login ='AuditUser'  
  53.    
  54.     select @ProgramName=[Program_Name]fromsys.dm_exec_sessionswheresession_id=@spid  
  55.     select @IP=client_net_addressfromsys.dm_exec_connectionswheresession_id=@spid  
  56.    
  57.     insert into DBAdminPlat.dbo.DBA_ChangedObjectLog(  
  58.        [LogId],  
  59.        [EventType],[PostTime],[SPID],[ServerName],[Host_IP_Address],[Host_MAC_Address],  
  60.        [ProgramName],[LoginName],[UserName],[DatabaseName],[SchemaName],  
  61.        [ObjectName],[ObjectType],[TSQLCommand]--,[EventDate]  
  62.     )  
  63.     values(  
  64.        @newid,  
  65.        @EventType,  
  66.        @data.value('(/EVENT_INSTANCE/PostTime)[1]','datetime'),  
  67.        @spid,  
  68.        @data.value('(/EVENT_INSTANCE/ServerName)[1]','varchar(256)'),  
  69.        @IP,  
  70.        @mac,  
  71.        @ProgramName,  
  72.        @LoginName,--@data.value('(/EVENT_INSTANCE/LoginName)[1]','varchar(256)'),  
  73.        @data.value('(/EVENT_INSTANCE/UserName)[1]','varchar(256)'),  
  74.        @data.value('(/EVENT_INSTANCE/DatabaseName)[1]','varchar(256)'),  
  75.        @data.value('(/EVENT_INSTANCE/SchemaName)[1]','varchar(256)'),  
  76.        @ObjectName,  
  77.        @ObjectType,  
  78.        --For objectslike procs, views, triggers and functions ,text of which will be stored inmaster.[dbo].[tb_dba_ChangedObjectText] table.  
  79.        case when @ObjectType in('PROCEDURE','VIEW','FUNCTION','TRIGGER')and(@EventType<>'GRANT_DATABASE'or@EventType like 'DROP%')and@IsaDDLTrigger=0  
  80.            then null else @data.value('(/EVENT_INSTANCE/TSQLCommand)[1]','varchar(max)')end  
  81.     );  
  82.    
  83.     REVERT;  
  84.    
  85. end  
  86.   
  87. GO  
  88.    
  89. SET ANSI_NULLSOFF  
  90. GO  
  91. SET QUOTED_IDENTIFIEROFF  
  92. GO  
  93. ENABLE TRIGGER[tr_dba_Trace_ObjectChangeLog]ON DATABASE  
  94. GO  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值