“执行为自我”vs跨数据库视图

时间:2018-04-20 16:18:40

标签: sql-server sql-server-2016

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域帐户。

我在这里缺少什么?

1 个答案:

答案 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拥有的对象的含义是数据库AB必须由同一登录拥有,以便为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