我对我所看到的行为有一个非常具体的问题,但无法弄明白。我会用代码引导你完成这个问题。
使用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可以突然查询该表。
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),但是当我特意想要执行另一个用户时,我希望能够检查该用户的权限。
答案 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');
证明用户U1在表T1或T2上没有SELECT权限。
EXECUTE AS USER = 'U1';
SELECT * FROM dbo.T1;
SELECT * FROM dbo.T2;
REVERT
创建两个存储过程并允许用户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
以用户U1执行过程P2。这会失败,因为所有权链已损坏,因此会检查存储过程中的权限。 P2和T2有不同的所有者。
EXECUTE AS USER = 'U1';
EXEC dbo.P2;
REVERT
接下来,演示存储过程在包含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;
执行P2A,这会失败。执行链断开,因此检查存储过程中的权限。
EXEC dbo.P2A;
请注意,我们在这些示例中使用了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