Как отфильтровать использование определяемой пользователем скалярной функции из данных аудита SQL Server?

12

У нас есть база данных SQL Server, которая имеет спецификацию аудита базы данных, которая проверяет все выполняемые действия в базе данных.

CREATE DATABASE AUDIT SPECIFICATION [dbAudit]
FOR SERVER AUDIT [servAudit]
ADD (EXECUTE ON DATABASE::[DatabaseName] BY [public])

Мы обнаружили, что некоторые запросы записывают в журнал аудита использование скалярной функции для каждой строки в наборе результатов. Когда это происходит, журнал заполняется до того, как мы сможем поместить его в место последнего упокоения, и у нас есть пробел в нашем журнале.

К сожалению, из-за соображений соответствия, мы не можем просто прекратить проверку каждого EXECUTEзаявления.

Нашей первой мыслью о подходе к этой проблеме является использование WHEREусловия аудита сервера для фильтрации действий. Код выглядел так:

WHERE [object_id] not in (Select object_id from sys.objects where type = 'FN' )

К сожалению, SQL Server не допускает реляционный оператор IN (возможно, потому что он не хочет запрашивать каждый раз, когда ему нужно записать в журнал аудита).

Мы хотели бы избежать написания хранимого процесса, который жестко кодирует object_idв WHEREпредложении, но это наш текущий взгляд на лучший способ решения этой проблемы. Есть ли альтернативный подход, который мы должны рассмотреть?

Мы заметили, что когда скалярная функция используется в рекурсивном CTE, она заставляет запрос записывать в журнал аудита для каждой строки в наборе результатов.

Существует несколько скалярных функций, предоставляемых поставщиком, которые мы не можем удалить или перенести в альтернативную базу данных.

Марк Яннуччи
источник
6
We've found that some queries will write to the audit log the use of a scalar function for every row in a result set.- Это один из самых великолепных побочных эффектов скалярных UDF, которые я когда-либо слышал, и я много слышал.
Эрик Дарлинг
3
Есть ли возможность создания UDF, которые вы не хотите проверять, в отдельной базе данных (которая не проверяется) и вызывать их через 3-part-name?
Скотт Ходжин
@ScottHodgin, мне нравится обходной путь, но в наших обстоятельствах есть некоторые скалярные функции, предоставляемые поставщиком, которые мы не можем удалить или перенести в альтернативную базу данных.
Марк Яннуччи
Последующим может быть интересно, в каком случае запрос записывается в журнал аудита для каждой строки в наборе результатов; мы заметили, что это происходит, когда скалярная функция используется в рекурсивном CTE.
Марк Яннуччи

Ответы:

6

Есть несколько вариантов, с которыми я смог работать. Все опции имеют дело с вариациями предикатов фильтра. ПРИМЕЧАНИЕ. Чтобы внести изменения, необходимо отключить аудит сервера, а затем снова включить его.

Во-первых, наиболее общий подход состоит в том, чтобы отфильтровать все скалярные UDF. Вы можете сделать это, используя class_typeполе аудита. В документации указано, что это поле есть VARCHAR(2), но оно не позволяет указывать строку. Тем не менее, я получил следующее для работы:

ALTER SERVER AUDIT [servAudit]
WHERE ([class_type] <> 20038); -- EXECUTE Scalar UDF

(более подробная информация об этом расследовании здесь: Тайна аудита сервера: фильтрация class_type получает сообщение об ошибке 25713 )

Следующий наиболее общий подход - не вариант, поскольку было указано, что это база данных, предоставляемая поставщиком, и, следовательно, изменения не могут быть внесены. Так что я расскажу об этом последнем.

Наименее универсальный подход (но он определенно работает) - отфильтровать имя конкретной функции:

ALTER SERVER AUDIT [servAudit]
WHERE ([object_name]<>'function_name');

Или, если несколько имен:

ALTER SERVER AUDIT [servAudit]
WHERE ([object_name]<>'function_name1' AND [object_name]<>'function_name2');

Хотя этот подход не очень общий, он должен подойти, так как количество отфильтрованных функций должно быть довольно небольшим, и не так часто будут появляться новые функции.

Наконец, для тех, кто сталкивается с этой ситуацией и не имеет ограничений для внесения изменений: вы можете поместить функции в их собственную схему, а затем отфильтровать только эту схему. Это более общий характер, чем индивидуальная фильтрация функций. Предполагая, что вы создали именованную схему fnи поместили в нее функции:

ALTER SERVER AUDIT [servAudit]
WHERE ([schema_name]<>'fn');

ТАКЖЕ, относительно следующих двух комментариев в вопросе:

К сожалению, SQL Server не допускает реляционный оператор IN (возможно, потому что он не хочет запрашивать каждый раз, когда ему нужно записать в журнал аудита).

и:

Мы хотели бы избежать написания хранимого процесса, который жестко кодирует object_id в предложении WHERE

INОператор не является проблемой. Правда, это не поддерживается, но это просто сокращение для списка ORусловий. Актуальная проблема - использование T-SQL. Разрешены только литералы - строки или числа. Так что вы не смогли бы выполнить хранимую процедуру в любом случае. Также вы не можете использовать встроенные функции.

Соломон Руцкий
источник
спасибо за этот ответ. Мы находимся в процессе внедрения этого изменения, и я приму этот ответ, когда мы подтвердим, что оно работает в нашей среде.
Марк Яннуччи
1
@MarkIannucci Спасибо! Кроме того, я только что исправил небольшую ошибку в своем идеальном предложении. Я скопировал и вставил из тестирования, где я фильтровал функции FOR вместо НИЧЕГО, НО функций. Я изменил, =чтобы быть <>в моем ответе. Я также только что проверил это, и это работает как рекламируется :-)
Соломон Руцки