SQL Server 2012 – Auditing SELECT of a Single Column
auditsql serversql-server-2012
Is this possible, or is table-level the most granular access?
So far, Google search has shown nothing, and this screenshot does not mention column, but I thought I'd ask here.
SQL Server version is 2012 SP4-OD.
Best Answer
Not knowing your systems or the load on them, I cannot stress enough the need to test this suggested solution, very thoroughly. However, that said, you can do this, partly, through Extended Events. Here's a sample script:
CREATE EVENT SESSION [ColumnAudit]
ON SERVER
ADD EVENT sqlserver.sp_statement_completed
(WHERE (
[sqlserver].[equal_i_sql_unicode_string]([sqlserver].[database_name], N'HamShackRadio')
AND [sqlserver].[like_i_sql_unicode_string]([statement], N'%RadioName%')
AND [sqlserver].[like_i_sql_unicode_string]([statement], N'%SELECT%')
)
),
ADD EVENT sqlserver.sql_statement_completed
(WHERE (
[sqlserver].[equal_i_sql_unicode_string]([sqlserver].[database_name], N'HamShackRadio')
AND [sqlserver].[like_i_sql_unicode_string]([statement], N'%RadioName%')
AND [sqlserver].[like_i_sql_unicode_string]([statement], N'%SELECT%')
)
);
A few notes on this.
First, I would strongly recommend that you put good filtering in place. I've filtered first on the database name in order to only capture this from the one database. Second, I've ensured that I can filter the statement for the columnname ahead of anything else to be sure I'm only looking at those statement. Then I filter on SELECT.
Second, lest you balk at all to use Extended Events, remember that Audit is just using them behind the scenes, so this is a normal use of the functionality offered.
Third, and most importantly, test this. I've no idea how a wild card filter like this is likely to behave on your system. If you have another way to add additional filters before the wild card, say, on object_id or something, I would.
Finally, this won't work if someone types SELECT * FROM dbo.MyTable. I'm not sure how I'd tackle attempting to capture that. I guess you could filter for SELECT, the table name, and *. That would probably do it.
In case I haven't emphasized it enough, test this thoroughly before you implement it in production.
Column level security does not work that way. I'm aware of no mechanism to globally deny access to a certain column for a given user. The GRANT/DENY only works on specific statements like SELECT, UPDATE and so on in combination with a given object.
So in your case, if you removed access on SELECT for column X on table Y the user can still happily execute "select *" views on that table because the view is a different object and is unaffected by this security setting!
The good news is that you can use column permissions on views also. It works just the same as with tables, but you have to set the permission on every view that includes the SSN column.
Controls the way the column stores values shorter than the defined size of the column, and the way the column stores values that have trailing blanks in char, varchar, binary, and varbinary data.
Best Answer
Not knowing your systems or the load on them, I cannot stress enough the need to test this suggested solution, very thoroughly. However, that said, you can do this, partly, through Extended Events. Here's a sample script:
A few notes on this.
First, I would strongly recommend that you put good filtering in place. I've filtered first on the database name in order to only capture this from the one database. Second, I've ensured that I can filter the statement for the columnname ahead of anything else to be sure I'm only looking at those statement. Then I filter on SELECT.
Second, lest you balk at all to use Extended Events, remember that Audit is just using them behind the scenes, so this is a normal use of the functionality offered.
Third, and most importantly, test this. I've no idea how a wild card filter like this is likely to behave on your system. If you have another way to add additional filters before the wild card, say, on object_id or something, I would.
Finally, this won't work if someone types SELECT * FROM dbo.MyTable. I'm not sure how I'd tackle attempting to capture that. I guess you could filter for SELECT, the table name, and *. That would probably do it.
In case I haven't emphasized it enough, test this thoroughly before you implement it in production.