加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > MsSql教程 > 正文

SQLServer2005下局部字段级查询语句获取(或审计)

发布时间:2020-12-12 14:55:01 所属栏目:MsSql教程 来源:网络整理
导读:只因为Oracle里面有自己的细粒度审计,也想看看SQLServer是否也对于查询进行完全审计。经过一番调研后,下面是详细的实现步骤 1 ?原表创建: create table PERFORMANCE_C ( ? PID ? ? ? ? ?INTEGER not null, ? PERSIONID ? ?VARCHAR(40), ? DATEFIELD ? ?DA

只因为Oracle里面有自己的细粒度审计,也想看看SQLServer是否也对于查询进行完全审计。经过一番调研后,下面是详细的实现步骤

1 ?原表创建:
create table PERFORMANCE_C
(
? PID ? ? ? ? ?INTEGER not null,
? PERSIONID ? ?VARCHAR(40),
? DATEFIELD ? ?DATETIME,
? NAME ? ? ? ? VARCHAR(40),
? ACCOUNT ? ? ?VARCHAR(20),
? BALANCE ? ? ?DECIMAL(9,2),
? SECURITYCODE VARCHAR(60)
);


2 在原有CLR工程基础上,添加文件:AuditSession.cs
? 关于文件的内容如下:

?主要是将审计到的文件写入到文件(C#实现)。

?//用于识别查询是否是第一次执行,(Key=@@SPID,Value=@@SPID+RAND())
? ? ? ? private static Hashtable g_OldAuditSQLStatus = System.Collections.Hashtable.Synchronized(new System.Collections.Hashtable());
?//用于存储当前每个连接对应的当前查询语句
? ? ? ? private static Hashtable g_AuditSQLTable = System.Collections.Hashtable.Synchronized(new System.Collections.Hashtable());

//此函数在一次查询中是被多次执行的
? ? ? ? public static SqlString SendAuditSql(SqlString colValue,SqlString auditSQL,SqlInt32 spid,SqlDouble randV)
? ? ? ? {
? ? ? ? ? ? if (auditSQL.IsNull)
? ? ? ? ? ? ? ? return colValue;
? ? ? ? ? ??
? ? ? ? ? // ? DebugLog.WriteLine(randV.Value.ToString());
? ? ? ? ? ? if (g_AuditSQLTable.Contains(spid))
? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? if (g_OldAuditSQLStatus[spid].Equals(randV))
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? if (g_AuditSQLTable[spid].Equals(auditSQL))
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? return colValue;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? else
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? DebugLog.WriteLine(auditSQL.Value);
? ? ? ? ? ? ? ? ? ? ? ? g_OldAuditSQLStatus[spid] = randV;
? ? ? ? ? ? ? ? ? ? ? ? g_AuditSQLTable[spid] = auditSQL;
? ? ? ? ? ? ? ? ? ? ? ? return colValue;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? else
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? DebugLog.WriteLine(auditSQL.Value);
? ? ? ? ? ? ? ? ? ? g_OldAuditSQLStatus[spid] = randV;
? ? ? ? ? ? ? ? ? ? g_AuditSQLTable[spid] = auditSQL;
? ? ? ? ? ? ? ? ? ? return colValue;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? else
? ? ? ? ? ? {
? ? ? ? ? ? ? ? DebugLog.WriteLine(auditSQL.Value);
? ? ? ? ? ? ? ? g_AuditSQLTable.Add(spid,auditSQL);
? ? ? ? ? ? ? ? g_OldAuditSQLStatus.Add(spid,randV);
? ? ? ? ? ? ? ? return colValue;
? ? ? ? ? ? }
? ? ? ? }

//写入到文件

private static void WirteFile(string val)?
? ? {
? ? ? ? string filePath = "c:/storeproc.log";
? ? ? ? FileStream fout = new FileStream(filePath,FileMode.Append);?
? ? ? ? StreamWriter ? fstr ? = ? new ? StreamWriter(fout);?
? ? ? ? fstr.WriteLine(val.ToString()); ?
? ? ? ? fstr.Close();?
? ? ? ? fstr ? = ? null;?
? ? ? ? fout ? = ? null;?
? ? }


3 注册CLR集的SQL语句:
--创建CLR集
CREATE ASSEMBLY DBCUDT
FROM 'D:ForVSProjectsdbcudtdbcudtbinDebugdbcudt.dll'
WITH PERMISSION_SET = UNSAFE;
GO

--需要打开数据库的TRUSTWORTHY 及CLR支持打开

--注册里面的相关函数

create FUNCTION dbo.Func_sendAuditSQL
? (@colValue NVARCHAR(4000),@auditStr NVARCHAR(4000),@sessionID int,@callTimes float)?
RETURNS Nvarchar(4000)
EXTERNAL NAME [DBCUDT].[schina.dbcoffer.dbcudt.AuditSession].[SendAuditSql];

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?--[your assembly].[space.class].[your function]
GO


4?5 创建获取审计语句的视图
CREATE view [dbo].[getSQL] as
select (?
when rand()>0
then (SELECT?
cast(text as varchar(max)) as auditSQL FROM?
(SELECT * FROM sys.dm_exec_sql_text(
(SELECT most_recent_sql_handle FROM sys.dm_exec_connections AS t?
WHERE (session_id = @@SPID))) AS dm_exec_sql_text_1) AS t1)?
else NULL end) as auditSQL;

--至于这里为什么要用到rand()及用到case逻辑,去读读SQLServer的不确定函数及预编译相关的内容,你会有不少收获的啦。

--此处主要是保证上面的查询在一次查询过程只执行一次,千万不将这个语法直接嵌到查询中,否则,你晓得的,慢上40倍左右。


5??创建callTimes视图,用于标识当前的查询语句(实则为一个伪列)
CREATE view [dbo].[vperCallTimes] as
select pid,
?persionid,
?datefield,
?name,
?account,
?balance,
?securitycode,
?rand() as callTimes
from dbo.performance_c;

--rand()主要是确定为一次查询

6 创建透明视图
CREATE view [dbo].[vper] as
select pid,
?dbo.Func_sendAuditSQL(persionid,(select auditSQL from [dbo].[getSQL]),@@spid,callTimes) as persionid,
?dbo.Func_sendAuditSQL(name,callTimes) as name,
?--name,
?securitycode
from dbo.vper1;


这样一来实现将审计到的语句写入到文件。

性能:

原表查询:1.457s(十万记录)

透明视图查询:1.691s(十万记录)

如果再作相关的优化,估计还能提高一百毫秒左右。

--缺点,查询字段假如不涉及改造字段,语句将不会被记录到文件。(正好符合要求,实现字段的查询审计)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读