为什么" exec as user"在proc中绕过权限检查?

时间:2016-05-09 04:47:12

标签: sql-server permissions sql-server-2012

我对我所看到的行为有一个非常具体的问题,但无法弄明白。我会用代码引导你完成这个问题。

使用sysadmin用户启动SSMS:

1。创建一个新的测试数据库

create database test

2。创建新登录

create login newuser with password='newuser', check_policy=off

第3。在测试数据库中创建用户并将其映射到登录

create user newuser for login newuser

4。创建一个新表并对其进行测试

create table dbo.newtable (id int identity(1, 1)) insert dbo.newtable default values select * from dbo.newtable

5。以新用户身份执行

此步骤将证明newuser对表没有SELECT权限。

exec as user = 'NewUser' select suser_sname() as [suser_sname()], original_login() as [original_login()] select * from dbo.NewTable revert

输出:

Msg 229, Level 14, State 5, Line 3
The SELECT permission was denied on the object 'newtable', database 'test', schema 'dbo'.

现在,下一步是有趣的开始。如果将上面的代码片段包装在proc中,您将看到newuser可以突然查询该表。

  1. 创建一个proc
  2. create proc dbo.newproc as exec as user = 'newuser' select suser_sname() as [suser_sname()], original_login() as [original_login()] select * from dbo.newtable revert go -- Note I haven't granted any permissions to newuser whatsoever. exec dbo.newproc

    输出:

    suser_sname()  original_login()
    ------------------------------------
    newuser        domain\louie.bao
    
    id
    --
    1

    任何人都可以向我解释一下在proc中执行相同代码的权限检查有何不同?

    修改

    即使您专门发出DENY,新用户仍然可以访问dbo.newtable,更令人不安的是:

    deny select on dbo.newtable to newuser exec dbo.newproc

    我知道所有权链接会授予对proc调用者的访问权限(在本例中为me),但是当我特意想要执行另一个用户时,我希望能够检查该用户的权限。

2 个答案:

答案 0 :(得分:2)

这是所有权链的问题。

请参阅联机丛书>所有权链:https://technet.microsoft.com/en-us/library/ms188676(v=sql.105).aspx

首先,我们可以演示所有权链如何工作,如果存储过程中没有EXECUTE AS,那么我们就可以看到它如何与EXECUTE AS一起工作。

创建两个表并插入数据。

CREATE TABLE dbo.T1 (id int IDENTITY(1,1));
CREATE TABLE dbo.T2 (id int IDENTITY(1,1));

INSERT INTO dbo.T1 DEFAULT VALUES;
INSERT INTO dbo.T2 DEFAULT VALUES;

创建两个用户。

CREATE USER U1 WITHOUT LOGIN;
CREATE USER U2 WITHOUT LOGIN;

将表T2的所有权更改为用户U2。

ALTER AUTHORIZATION ON OBJECT::dbo.T2 TO U2;

确认我们已更改了所有权。

SELECT name, principal_id
    FROM sys.tables
    WHERE name IN (N'T1', N'T2');

enter image description here

证明用户U1在表T1或T2上没有SELECT权限。

EXECUTE AS USER = 'U1';
SELECT * FROM dbo.T1;
SELECT * FROM dbo.T2;
REVERT

enter image description here

创建两个存储过程并允许用户U1执行这两个过程。

CREATE PROCEDURE dbo.P1
AS 
    SELECT * FROM dbo.T1;
GO  
CREATE PROCEDURE dbo.P2
AS 
    SELECT * FROM dbo.T2;
GO

GRANT EXECUTE ON dbo.P1 to U1;
GRANT EXECUTE ON dbo.P2 to U1;

以用户U1执行P1。这是有效的,因为有一个不间断的所有权链。 P1和T1具有相同的所有者(模式dbo的所有者)。在这种情况下,将跳过存储过程内的权限检查。

EXECUTE AS USER = 'U1';
EXEC dbo.P1;
REVERT

enter image description here

以用户U1执行过程P2。这会失败,因为所有权链已损坏,因此会检查存储过程中的权限。 P2和T2有不同的所有者。

EXECUTE AS USER = 'U1';
EXEC dbo.P2;
REVERT

enter image description here

接下来,演示存储过程在包含EXECUTE AS时的工作方式。

再创建两个存储过程。

CREATE PROCEDURE dbo.P1A
AS 
    EXECUTE AS USER = 'U1';
    SELECT * FROM dbo.T1;
    REVERT
GO  
CREATE PROCEDURE dbo.P2A
AS 
    EXECUTE AS USER = 'U1';
    SELECT * FROM dbo.T2;
    REVERT
GO

执行P1A,这有效。不间断的执行链,因此不会检查存储过程中的权限。

EXEC dbo.P1A;

enter image description here

执行P2A,这会失败。执行链断开,因此检查存储过程中的权限。

EXEC dbo.P2A;

enter image description here

请注意,我们在这些示例中使用了EXECUTE AS语句。还有一个EXECUTE AS子句,它与存储过程,函数和触发器一起使用。

联机丛书> EXECUTE AS(Transact-SQL):https://msdn.microsoft.com/en-us/library/ms181362.aspx

联机丛书> EXECUTE AS子句(Transact-SQL):https://msdn.microsoft.com/en-GB/library/ms188354.aspx

答案 1 :(得分:1)

由于“所有权链接”,这是正常行为

在内部例程中,如果引用的表具有与存储过程相同的AUTHORIZATION,则不会检查权限。在这种情况下,它们都处于“dbo”架构中,因此不会检查权限。这包括DENY权限

create proc dbo.newproc2
with EXECUTE AS CALLER
as
select * from dbo.newtable
GO

GRANT EXEC ON dbo.newproc2 TO newuser
EXEC as user = 'newuser'
exec dbo.newproc2
REVERT


GO

DENY SELECT ON dbo.newtable TO newuser
exec dbo.newproc
GO
EXEC as user = 'newuser'
exec dbo.newproc2
REVERT
GO