SQL Server 2016.数据库A
中有一个视图,可以从另一个数据库B
中的表中进行选择:
use A
go
create view TheView as
select * from B.dbo.SomeTable
我有B
数据库的dbo访问权限,我可以查询我想要的所有内容:
select * from TheView -- Works as expected
现在我已经创建了一个带有EXECUTE AS SELF
子句的过程,希望它能像我一样执行:
use A
go
create proc dbo.f
with execute as self
as
select * from TheView
当我运行它时,我得到以下内容:
服务器主体“ACME \ seva”无法在当前安全上下文中访问数据库“B”。
如果我删除了execute as
子句,则该过程按预期运行。
我使用集成安全性连接Windows域帐户。
我在这里缺少什么?
答案 0 :(得分:2)
TRUSTWORTHY
,否则 EXECUTE AS
模拟将沙箱映射到当前数据库。不要打开TRUSTWORTHY数据库选项,而应考虑采用不那么严厉的方法来扩展跨数据库的安全性。跨数据库提供非特权用户权限的方法包括:
<强> DB_CHAINING:强>
DB_CHAINING ON
允许标准的数据库内所有权链接扩展到数据库,以便不需要对间接访问的对象的权限。只要所有权链未被中断,用户只需要对dbo.f
存储过程执行权限。请注意,用户仍将是数据库B中的用户,但不需要授予对象权限。例如:
ALTER DATABASE A SET DB_CHAINING ON;
ALTER DATABASE B SET DB_CHAINING ON;
DB_CHAINING和dbo拥有的对象的含义是数据库A
和B
必须由同一登录拥有,以便为dbo
用户维护一个完整的所有权链。如果需要,可以使用ALTER AUTHORIZATION更改数据库所有者:
ALTER AUTHORIZATION ON DATABASE::A to DatabaseOwnerLogin;
ALTER AUTHORIZATION ON DATABASE::B to DatabaseOwnerLogin;
模块签名:
Module signing允许用户通过证书用户向模块添加其他权限。创建证书,从证书创建用户,向证书用户授予所需权限,然后使用证书对存储过程进行签名。以下是从this article收集的示例代码。
通过DB_CHAINING进行模块签名的一个优点是,调用用户不需要是数据库B中的用户,因为cert用户提供了安全上下文。请注意,如果稍后更改了proc,则需要重新签名。
USE B;
-- create certifciate, cert user, and grant needed permissions
CREATE CERTIFICATE cross_database_cert
ENCRYPTION BY PASSWORD = 'All you need is love'
WITH SUBJECT = 'For cross-database access';
CREATE USER cross_database_cert FROM CERTIFICATE cross_database_cert;
GRANT SELECT ON dbo.SomeTable TO cross_database_cert;
GO
-- Copy cert to database A
DECLARE @cert_id int = cert_id('cross_database_cert')
DECLARE @public_key varbinary(MAX) = certencoded(@cert_id),
@private_key varbinary(MAX) =
certprivatekey(@cert_id,
'All you need is love',
'All you need is love')
SELECT @cert_id, @public_key, @private_key
DECLARE @sql nvarchar(MAX) =
'CREATE CERTIFICATE cross_database_cert
FROM BINARY = ' + convert(varchar(MAX), @public_key, 1) + '
WITH PRIVATE KEY (BINARY = ' +
convert(varchar(MAX), @private_key, 1) + ',
DECRYPTION BY PASSWORD = ''All you need is love'',
ENCRYPTION BY PASSWORD = ''All you need is love'')'
EXEC A.sys.sp_executesql @sql;
GO
ALTER CERTIFICATE cross_database_cert REMOVE PRIVATE KEY;
GO
USE A;
GO
--sign proc with certificate
ADD SIGNATURE TO dbo.f BY CERTIFICATE cross_database_cert
WITH PASSWORD = 'All you need is love';
GO
ALTER CERTIFICATE cross_database_cert REMOVE PRIVATE KEY;
GO