关于我看到但无法弄清楚的行为,我有一个非常具体的问题。我将通过代码引导您完成这个问题。
以系统管理员用户启动 SSMS:
<强>1。新建一个测试数据库
创建数据库测试
<强>2。创建一个新的登录名
使用 password='newuser', check_policy=off 创建登录新用户
<强>3。在测试数据库中创建一个用户并将其映射到登录
为登录newuser创建用户newuser
<强>4。创建一个新表并测试它
创建表 dbo.newtable (id int identity(1, 1))
插入 dbo.newtable 默认值
从 dbo.newtable 中选择 *
<强>5。以新用户身份执行
这一步将证明newuser对该表没有SELECT权限。
exec as user = 'NewUser'
选择 suser_sname() 作为 [suser_sname()],original_login() 作为 [original_login()]
从 dbo.NewTable 中选择 *
还原
输出:
Msg 229, Level 14, State 5, Line 3 The SELECT permission was denied on the object 'newtable', database 'test', schema 'dbo'.
现在,下一步就是乐趣的开始。如果将上面的代码片段包装在一个 proc 中,您会看到 newuser 可以突然查询该表。
- 创建过程
创建过程 dbo.newproc
作为
以用户身份执行='新用户'
选择 suser_sname() 作为 [suser_sname()],original_login() 作为 [original_login()]
从 dbo.newtable 中选择 *
恢复
走
-- 注意我没有授予新用户任何权限。
执行 dbo.newproc
输出:
suser_sname() original_login() ------------------------------------ newuser domain\louie.bao id -- 1
任何人都可以向我解释一下在 proc 中执行相同代码的权限检查有何不同?
编辑
更麻烦的是,即使您专门发出 DENY,newuser 仍然可以访问 dbo.newtable:
拒绝在 dbo.newtable 上选择新用户
执行 dbo.newproc
我知道所有权链将授予 proc 调用者(在本例中是我)的访问权限,但是当我特别想以另一个用户身份执行时,我希望检查该用户的权限。
最佳答案
这是所有权链的问题。
参见联机丛书 > 所有权链: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
关于sql-server - 为什么 "exec as user"可以绕过proc中的权限检查?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37107886/