sql-server - 为什么 "exec as user"可以绕过proc中的权限检查?

标签 sql-server permissions sql-server-2012

关于我看到但无法弄清楚的行为,我有一个非常具体的问题。我将通过代码引导您完成这个问题。

以系统管理员用户启动 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 可以突然查询该表。

  1. 创建过程

创建过程 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');

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

关于sql-server - 为什么 "exec as user"可以绕过proc中的权限检查?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37107886/

相关文章:

c# - 如何按表列过滤 LINQ 查询并获取计数

sql - 为什么插入和加入#temp 表更快?

docker - 为什么容器外的目录层次结构的 docker cp 会因权限被拒绝而失败?

sql-server - TSQL : Can't concatenate strings in while loop

sql-server - 自增主键生成奇怪的值

sql - sql server如何将多行合并为一个字段

linux - *nix 中的打印机配置文件

Ruby 设法以只读方式打开 644 文件失败

SQL Server 查询 : Adjust money column

smo - SQL Server 2012 小程序