如何从 SQL Server 审计数据中过滤掉标量值用户定义函数的使用情况?

Mar*_*cci 12 sql-server audit cte functions recursive

我们有一个 SQL Server 数据库,它有一个数据库审计规范,它审计对数据库的所有执行操作。

CREATE DATABASE AUDIT SPECIFICATION [dbAudit]
FOR SERVER AUDIT [servAudit]
ADD (EXECUTE ON DATABASE::[DatabaseName] BY [public])
Run Code Online (Sandbox Code Playgroud)

我们发现,某些查询会将结果集中的每一行的标量函数的使用写入审计日志。当这种情况发生时,日志在我们可以 ETL 到它的最终休息位置之前就被填满了,我们的日志记录出现了空白。

不幸的是,由于合规性原因,我们不能简单地停止审核每条EXECUTE语句。

我们解决这个问题的第一个想法是使用Server AuditWHERE上的子句来过滤掉活动。代码如下所示:

WHERE [object_id] not in (Select object_id from sys.objects where type = 'FN' )
Run Code Online (Sandbox Code Playgroud)

不幸的是,SQL Server 不允许关系 IN 运算符(可能是因为它不想在每次必须写入审核日志时进行查询)。

我们想避免编写一个存储过程,其硬代码object_idWHERE条款,但是这是我们在解决这个问题的最好办法目前的想法。是否有我们应该考虑的替代方法?

我们注意到,当在递归 CTE 中使用标量函数时,它会导致查询为结果集中的每一行写入审计日志。

有一些标量值函数由供应商提供,我们无法删除或移动到备用数据库。

Sol*_*zky 6

有几个选项可以让我开始工作。所有选项都处理过滤谓词的变体。注意:您必须禁用服务器审计才能进行更改,然后重新启用它。

首先,最通用的方法是过滤掉所有标量 UDF。您可以通过使用class_type审计字段来做到这一点。文档表明该字段是VARCHAR(2),但它不允许指定字符串。但是,我确实得到了以下工作:

ALTER SERVER AUDIT [servAudit]
WHERE ([class_type] <> 20038); -- EXECUTE Scalar UDF
Run Code Online (Sandbox Code Playgroud)

(有关该调查的更多信息:Server Audit Mystery: Filtering class_type gets Error Msg 25713

下一个最通用的方法不是一个选项,因为它被声明为供应商提供的数据库,因此不能进行任何更改。所以我会在最后介绍这一点。

最不通用的方法(但绝对有效的方法)是过滤掉特定的函数名称:

ALTER SERVER AUDIT [servAudit]
WHERE ([object_name]<>'function_name');
Run Code Online (Sandbox Code Playgroud)

或者,如果有多个名称:

ALTER SERVER AUDIT [servAudit]
WHERE ([object_name]<>'function_name1' AND [object_name]<>'function_name2');
Run Code Online (Sandbox Code Playgroud)

虽然不是很通用,但这种方法应该没问题,因为要过滤掉的函数数量应该很少,而且不会经常引入新函数。

最后,对于面临这种情况并且不受限制进行更改的其他人:您可以将函数放入他们自己的 Schema 中,然后仅过滤掉该 Schema。这比单独过滤掉函数更通用。假设您创建了一个名为的 Schema 并将fn函数放入其中:

ALTER SERVER AUDIT [servAudit]
WHERE ([schema_name]<>'fn');
Run Code Online (Sandbox Code Playgroud)

另外,关于问题中的以下两条评论:

不幸的是,SQL Server 不允许关系 IN 运算符(可能是因为它不想在每次必须写入审核日志时进行查询)。

和:

我们希望避免编写在 WHERE 子句中对 object_id 进行硬编码的存储过程

IN操作不是问题。确实,它不受支持,但它只是OR条件列表的简写。实际问题是 T-SQL 的使用。只允许使用文字——字符串或数字。因此,无论如何您都无法执行存储过程。您也不能使用内置函数。