SQL Server: EXECUTE AS clause of stored procedure not granting sysadmin permissions

眉间皱痕 提交于 2019-12-10 20:31:48

问题


I developped a stored procedure in order to restore a database from a backup file and add an application user to it. This stored procedure belongs to the master database.

The issue is that my IT department does not allow me to use an admin user, only to use an EXECUTE AS statement with a sysadmin user.

I can restore the database but I can't find a way to add the user at the end of the process.

The code I use:

CREATE PROCEDURE [dbo].[myProc] 
@database VARCHAR(50)
WITH EXECUTE AS 'aSysAdminUser' 
AS
BEGIN
    --Restore the database (working)
    --Add the application user    (not working)                  
    SET @sqlScript = 'USE '+@database +';
    CREATE USER [myApplicationUser] FROM LOGIN [myApplicationUser];
    EXEC sp_addrolemember ''db_owner'', ''myApplicationUser'''
    EXEC(@sqlScript)
END

When I run it, I have the following error message:

The server principal "aSysAdminUser" is not able to access the database "database" under the current security context.

Any idea how I could create a user in a dynamic parameter db name from a stored procedure on master db using a EXECUTE AS statement?

Thanks


回答1:


The issue you are facing is a limitation of Impersonation (i.e. switching the security context via EXECUTE AS). For database-scoped objects, such as stored procedures you are specifying a database-level user in the EXECUTE AS clause, not a server-level login. Hence, this procedure is not really acting as a sysadmin. But, there is a way to safely grant just this one stored procedure true sysadmin permissions that will allow it to do the steps in your dynamic SQL, namely:

  1. CONNECT to the database
  2. CREATE USER
  3. ALTER ROLE

The way to do this is through signing the stored procedure with a certificate. The certificate will then also be used to create a server-level login that will be added to the sysadmin server role. Then, when any user / login (that has EXECUTE permission on this stored procedure) executes this procedure, it will pick up the permissions of the certificate-based login merely by being signed by the same certificate.

Step 1: Set up the certificate in the [master] database:

USE [master];
GO

CREATE CERTIFICATE [BackupRestoreCert]
    ENCRYPTION BY PASSWORD = N'MyPassword'
    WITH SUBJECT = N'Certificate for Managing Backup/Restore Operation Permissions';
GO

Step 2: Create the login and add to the sysadmin role:

CREATE LOGIN [BackupRestoreOps] FROM CERTIFICATE [BackupRestoreCert];

ALTER SERVER ROLE [sysadmin] ADD MEMBER [BackupRestoreOps];

Step 3: Sign the stored procedure with that certificate, creating the link to the new login:

ADD SIGNATURE
    TO [dbo].[myProc]
    BY CERTIFICATE [BackupRestoreCert]
    WITH PASSWORD = 'MyPassword';

All of the above is actually done within the context of the [master] database, though it seemed more readable for explanation to have it broken up. But, in practice it would be a single script that the IT folks run once. Of course, if you ever ALTER that stored procedure, they will have to run the ADD SIGNATURE command again (i.e. Step 3) as it is lost upon any changes to the definition of the procedure.

And that is that. I have tested this with the stored procedure shown in the question and it did, once I added the signature and the sysadmin role, create the user and add it to the db_owner role.

Step 4 (maybe): You could probably remove the EXECUTE AS clause from the stored procedure. If there were any permissions that it did pass on that allowed the initial restore operation(s) to work, those should be now assumed via the certificate-based login as it is marked as sysadmin.


DISCLAIMER
I just want / need to make clear that it is understood that, given the stored procedure specified in the question, as it is written, will allow for SQL Injection once this permission is granted. This, of course, was already a consequence of the original intention of the IT staff's decision to use the EXECUTE AS clause to grant sysadmin permissions to this stored procedure. I am just pointing it out now that the above steps will actually make their intended behavior a reality. If there are steps above the dynamic SQL that would error if anything other than a database name were passed in, then great, but this still needs to be stated for others who might be looking to duplicate this and just copying / pasting without understanding the full context.

There are two things that should be done:

  1. While a minor point, the datatype of the input parameter should be sysname (alias for NVARCHAR(128)) as that is how [name] is defined in [sys].[databases].
  2. The main thing to do is verify that the value passed in is an existing database name, something along the lines of:

    IF (DB_NAME(@database) IS NULL)
    BEGIN
       RAISERROR(N'Invalid Database Name', 16, 1);
       RETURN;
    END;
    

EDIT:
I have tried finding another server role that would allow for this that is not sysadmin in the hopes of not using such a privileged role. I have tried dbcreator, securityadmin, serveradmin, and setupadmin, but unfortunately none of them worked :(.



来源:https://stackoverflow.com/questions/26599324/sql-server-execute-as-clause-of-stored-procedure-not-granting-sysadmin-permissi

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!