SQL 服务器所有权链接是否不适用于 ALTER?
Does SQL Server ownership chaining not work for ALTER?
我有一个案例 SQL 服务器所有权链接似乎不起作用 - 还是我遗漏了什么?
我有两个架构:Schema1
和 Schema2
。
在Schema1
中,我只有SELECT
权限,而在Schema2
中,我只有EXEC
权限。
我在 Schema2
中调用了一个存储过程,它将一条记录插入到 Schema1
中的 table 中。
由于所有权链,这工作正常(即使我在 Schema1
中没有 INSERT
权限)。
现在,当我调用另一个在插入之前关闭 table 中的标识列的存储过程时,我得到一个错误:
Msg 1088, Level 16, State 11, Procedure Schema2.AddRecordWithSpecificId, Line 7 [Batch Start Line 60]
Cannot find the object "Schema1.MyTable" because it does not exist or you do not have permissions.
如果我向 Schema1
授予 ALTER
权限,它工作正常 - 但为什么有必要这样做?为什么模式链接在这种情况下不起作用?
重现问题的脚本:
CREATE DATABASE OwnershipChainingTest
GO
USE OwnershipChainingTest
GO
CREATE SCHEMA Schema1 AUTHORIZATION [dbo]
GO
CREATE SCHEMA Schema2 AUTHORIZATION [dbo]
GO
CREATE TABLE Schema1.MyTable
(
Id int IDENTITY(1,1) NOT NULL,
Title varchar(50) NOT NULL
)
GO
CREATE PROCEDURE Schema2.AddRecord
@title nvarchar(100)
AS
BEGIN
INSERT INTO Schema1.MyTable (Title)
VALUES (@title)
END
GO
CREATE PROCEDURE Schema2.AddRecordWithSpecificId
@id int,
@title nvarchar(100)
AS
BEGIN
SET IDENTITY_INSERT Schema1.MyTable ON
INSERT INTO Schema1.MyTable (Id, Title)
VALUES (@id, @title)
SET IDENTITY_INSERT Schema1.MyTable OFF
END
GO
CREATE USER MyUser WITHOUT LOGIN
GO
CREATE ROLE MyRole AUTHORIZATION [dbo]
GO
EXEC sp_addrolemember MyRole, MyUser
GO
-- With this it works: GRANT SELECT, ALTER ON Schema::Schema1 TO MyRole
GRANT SELECT ON Schema::Schema1 TO MyRole
GO
GRANT EXEC ON Schema::Schema2 TO MyRole
GO
EXEC AS user = 'MyUser'
EXEC Schema2.AddRecord 'hello1'
GO
-- This causes an error
EXEC Schema2.AddRecordWithSpecificId 42, 'hello2'
GO
REVERT;
--SELECT CURRENT_USER
SELECT * FROM Schema1.MyTable
USE MASTER
DROP DATABASE OwnershipChainingTest
GO
所有权链接仅适用于 DML。 SET IDENTITY_INSERT
本质上是一个 DDL 操作,这就是为什么它至少需要对 table.
的 ALTER
权限
允许仅具有 运行 proc 执行权限的最低特权用户的一个好方法是使用基于具有 ALTER
权限的用户的证书对 proc 进行签名:
--create certificate and sign proc
CREATE CERTIFICATE AddRecordWithSpecificIdCert
ENCRYPTION BY PASSWORD = 'temporary password'
WITH SUBJECT = 'Allow ALTER on Schema1';
ADD SIGNATURE TO Schema2.AddRecordWithSpecificId BY CERTIFICATE AddRecordWithSpecificIdCert WITH PASSWORD = 'temporary password';
--remove ephemeral private key
ALTER CERTIFICATE AddRecordWithSpecificIdCert REMOVE PRIVATE KEY;
--create a user from certificate with the needed permissions
CREATE USER AddRecordWithSpecificIdCertUser FROM CERTIFICATE AddRecordWithSpecificIdCert;
GRANT ALTER ON SCHEMA::Schema1 TO AddRecordWithSpecificIdCertUser;
GO
--this test now works
EXEC AS user = 'MyUser';
GO
EXEC Schema2.AddRecordWithSpecificId 42, 'hello2'
GO
REVERT;
GO
我有一个案例 SQL 服务器所有权链接似乎不起作用 - 还是我遗漏了什么?
我有两个架构:Schema1
和 Schema2
。
在Schema1
中,我只有SELECT
权限,而在Schema2
中,我只有EXEC
权限。
我在 Schema2
中调用了一个存储过程,它将一条记录插入到 Schema1
中的 table 中。
由于所有权链,这工作正常(即使我在 Schema1
中没有 INSERT
权限)。
现在,当我调用另一个在插入之前关闭 table 中的标识列的存储过程时,我得到一个错误:
Msg 1088, Level 16, State 11, Procedure Schema2.AddRecordWithSpecificId, Line 7 [Batch Start Line 60]
Cannot find the object "Schema1.MyTable" because it does not exist or you do not have permissions.
如果我向 Schema1
授予 ALTER
权限,它工作正常 - 但为什么有必要这样做?为什么模式链接在这种情况下不起作用?
重现问题的脚本:
CREATE DATABASE OwnershipChainingTest
GO
USE OwnershipChainingTest
GO
CREATE SCHEMA Schema1 AUTHORIZATION [dbo]
GO
CREATE SCHEMA Schema2 AUTHORIZATION [dbo]
GO
CREATE TABLE Schema1.MyTable
(
Id int IDENTITY(1,1) NOT NULL,
Title varchar(50) NOT NULL
)
GO
CREATE PROCEDURE Schema2.AddRecord
@title nvarchar(100)
AS
BEGIN
INSERT INTO Schema1.MyTable (Title)
VALUES (@title)
END
GO
CREATE PROCEDURE Schema2.AddRecordWithSpecificId
@id int,
@title nvarchar(100)
AS
BEGIN
SET IDENTITY_INSERT Schema1.MyTable ON
INSERT INTO Schema1.MyTable (Id, Title)
VALUES (@id, @title)
SET IDENTITY_INSERT Schema1.MyTable OFF
END
GO
CREATE USER MyUser WITHOUT LOGIN
GO
CREATE ROLE MyRole AUTHORIZATION [dbo]
GO
EXEC sp_addrolemember MyRole, MyUser
GO
-- With this it works: GRANT SELECT, ALTER ON Schema::Schema1 TO MyRole
GRANT SELECT ON Schema::Schema1 TO MyRole
GO
GRANT EXEC ON Schema::Schema2 TO MyRole
GO
EXEC AS user = 'MyUser'
EXEC Schema2.AddRecord 'hello1'
GO
-- This causes an error
EXEC Schema2.AddRecordWithSpecificId 42, 'hello2'
GO
REVERT;
--SELECT CURRENT_USER
SELECT * FROM Schema1.MyTable
USE MASTER
DROP DATABASE OwnershipChainingTest
GO
所有权链接仅适用于 DML。 SET IDENTITY_INSERT
本质上是一个 DDL 操作,这就是为什么它至少需要对 table.
ALTER
权限
允许仅具有 运行 proc 执行权限的最低特权用户的一个好方法是使用基于具有 ALTER
权限的用户的证书对 proc 进行签名:
--create certificate and sign proc
CREATE CERTIFICATE AddRecordWithSpecificIdCert
ENCRYPTION BY PASSWORD = 'temporary password'
WITH SUBJECT = 'Allow ALTER on Schema1';
ADD SIGNATURE TO Schema2.AddRecordWithSpecificId BY CERTIFICATE AddRecordWithSpecificIdCert WITH PASSWORD = 'temporary password';
--remove ephemeral private key
ALTER CERTIFICATE AddRecordWithSpecificIdCert REMOVE PRIVATE KEY;
--create a user from certificate with the needed permissions
CREATE USER AddRecordWithSpecificIdCertUser FROM CERTIFICATE AddRecordWithSpecificIdCert;
GRANT ALTER ON SCHEMA::Schema1 TO AddRecordWithSpecificIdCertUser;
GO
--this test now works
EXEC AS user = 'MyUser';
GO
EXEC Schema2.AddRecordWithSpecificId 42, 'hello2'
GO
REVERT;
GO