Imagine the following scenario



USE test;    

CREATE TABLE dbo.Customer
     CustomerId   INT,
     Email        VARCHAR(100),
     SensitiveData VARCHAR(20)

INSERT INTO dbo.Customer
VALUES     (1,'abc@foo.com','12346789');

At some point an ETL process is written that performs some activities in the test database.

CREATE USER etlUser WITHOUT LOGIN; /*For demo purposes*/

CREATE TABLE dbo.StagingTable
     StagingTableId INT,
     SomeData       VARCHAR(100),


DENY SELECT ON dbo.Customer TO etlUser;
DENY SELECT ON dbo.Customer (SensitiveData) TO etlUser; /*For good measure*/

The etlUser should not have permissions to the Customer table (and certainly not to the SensitiveData column) so these are explicitly denied above.

The ETL process truncates dbo.StagingTable so is given ALTER table permissions on that.

This is flagged during a security audit. How dangerous is this scenario?

  • Why are relatively harmless actions like ALTER TABLE ADD COLUMN treated the same as the other actions (ALTER, DROP, constraints, triggers)? – smci Apr 14 '18 at 22:56

Pretty dangerous...

In addition to the obvious permission to change the structure of StagingTable itself the ALTER TABLE permission allows them to create triggers on the table. So in this case through ownership chaining they are able to both see sensitive customer data (despite the explicit DENY permissions) and perform vandalism on this second table.

EXECUTE AS user='etlUser'


/*Exposure of sensitive data*/
SELECT * FROM dbo.Customer;

DELETE FROM dbo.Customer;


--Fire the trigger
UPDATE dbo.StagingTable SET SomeData = SomeData WHERE 1=0;

| improve this answer | |

In addition to being able to add triggers, the ALTER TABLE permission also allows for:

  1. Disabling triggers (avoid audit trail)
  2. Disable constraints (allowing for bad data)
  3. Altering contraints (allowing for bad data)
  4. Altering column definitions (change datatype, max size, NULLability)
  5. Add a computed column that calls a T-SQL UDF (making it very difficult to get a parallel plan, which could easily hurt performance)

It also allows for removing columns, but that is not likely to go unnoticed (since it seems that we are looking for potential actions here that are more deceptive than malicious).

Fortunately, it is never necessary to grant this permission to anyone, nor is it necessary to wrap this in a stored procedure that uses the EXECUTE AS clause (typically followed by 'dbo' or OWNER). Module Signing allows for easy abstraction of privileged actions behind signed code (stored procedures, triggers, scalar UDFs, and multi-statement TVFs). I have example code showing how to accomplish this in the following answers, here on DBA.SE:

The difference between those two answers is the permission granted to the signature-based User. The permission to be granted (or DB Role to be added to) depends on the scope of what is needed. If you only need permission for a single table, then only grant ALTER on that table. If permission is needed for all tables in a specific Schema, then don't grant permission to individual tables, but instead grant the permission to the Schema itself. And so on.

Module signing is a few extra steps as compared to creating a schema specifically for the ETL user, or using the EXECUTE AS clause, but:

  1. it is really just a simple copy and paste given that the code is available in both answers linked above, and
  2. it is certainly the most secure option available. It only allows that operation via that piece of code, and only to those given EXECUTE permission to that code. Being a Schema owner allows for certain implicit permissions that are unnecessary. And, using EXECUTE AS 'dbo' or EXECUTE AS OWNER (assuming the owner is dbo) will give the entire process, from that point forward, dbo permissions, not just the stored procedure / trigger / function that you used EXECUTE AS with. Module signing confines the permissions to only the code that you signed, and not any code called by the signed code.
| improve this answer | |
  • 2
    With some systems (at least some MySQL versions) there is a really dastardly way to effectively obliterate a VARCHAR column without it being instantly noticed by programs erroring out: reduce its size to 0. This will clear it out, and silently discard anything written to it... – rackandboneman Apr 14 '18 at 21:28

A better practice would be to create a staging schema, owned by the ETL user. Then the ETL process can truncate tables, disable constraints, perform partition switching, etc within the staging schema. The ETL user would only need limited permission on the other schemas.

You can also use a database role instead of a single user.

Of course you can also enable your limited user to perform table truncations with a dbo-owned stored procedure, like this:

create procedure truncate_t 
with execute as owner
  truncate table t;
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.