基于另一个数据库中的表的访问视图,而另一个数据库中没有帐户


10

我基于database2中的表在database1中创建了视图。我SELECT授予了只能访问database1的用户权限。用户无法使用此视图,因为他在database2中没有帐户。我该如何解决这个问题?我不想在database2中创建一个帐户。


1
@mustaccio不,这不是其他问题的重复,因为这种情况都在同一数据库中,并且此问题与跨数据库有关。默认情况下是不允许的。必须启用跨数据库所有权链接,这是一个巨大的安全漏洞,可满足如此狭窄的需求。
所罗门·鲁兹基

1
@SolomonRutzky,我不会将DB_CHAINING称为“巨大的安全漏洞”。在只有sysadmin角色成员可以创建对象的典型生产环境中,这不是问题。也就是说,在非sysadmin角色成员对除其拥有的架构之外的其他架构具有控制权限的情况下,应谨慎使用。
Dan Guzman

@DanGuzman“相信我,一切都会按计划进行”不是有效的策略。按照这种逻辑,TRUSTWORTHY ON将应用程序设置为或以进行登录几乎没有风险sa。数据库所有权链接之所以TRUSTWORTHY存在,主要是因为它是当时唯一的解决方案。但是现在,即使不是很大的风险,数据库链接也无疑是不必要的风险,因为模块签名并不那么困难。而且,如果人们依靠数据库链接然后使用动态SQL,则他们更有可能TRUSTWORTHY ON进行修复,而使用模块签名就不会损坏。
所罗门·鲁兹基

@SolomonRutzky,如果问题是关于模块而不是视图,我会建议模块签名。我的想法是,DB_CHAINING当对象无论如何都应该位于同一数据库中时,这没有数据库内部所有权链接那么危险。
丹·古兹曼

@DanGuzman为什么要假设“这些对象无论如何都应该位于同一数据库中”?OP仅表示相反的意思,因为他们希望保持数据库访问权限分离。OP使用View的原因是我建议使用TVF而不是存储过程的原因,但这并不意味着继续使用View是最佳的做法。通常建议在有意义的情况下修改结构和/或方法,例如此处的情况。尽管如此,我还是在答案中添加了可选的包装视图。并且,鉴于“ dbo”拥有所有东西是最常见的,是的,这DB_CHAINING是相当冒险的。
所罗门·鲁兹基

Answers:


9

使用模块签名很容易以非常安全的方式完成此操作。这将与下面的两个答案类似,也在DBA.StackExchange上,给出了执行此操作的示例:

具有执行方式,跨数据库查询和模块签名的存储过程安全性

使用跨数据库证书时触发器中的权限

此特定问题的不同之处在于,它处理一个视图,并且无法对视图进行签名。因此,您将需要将View更改为多语句表值函数(TVF),因为可以对它们进行签名并且可以像View一样对其进行访问(嗯,可以SELECT访问)。

下面的示例代码显示了该问题所要求的内容,即登录名/用户“ RestrictedUser”仅有权访问“ DatabaseA”,但仍能够从“ DatabaseB”获取数据。仅通过从一个TVF中进行选择,并且仅由于已对其进行签名,才能起作用。

要在仍然使用View的情况下实现这种跨数据库访问,并且给用户任何其他权限,则需要启用跨数据库所有权链接。它的安全性要差得多,因为它对两个数据库之间的所有对象都是完全开放式的(不能仅限于某些对象和/或用户)。模块签名仅允许该一个TVF拥有跨数据库访问权限(用户没有权限,TVF拥有权限),并且不能SELECT从TVF获得权限的用户根本无法访问“ DatabaseB”。

USE [master];

CREATE LOGIN [RestrictedUser] WITH PASSWORD = 'No way? Yes way!';
GO

---

USE [DatabaseA];

CREATE USER [RestrictedUser] FOR LOGIN [RestrictedUser];

GO
CREATE FUNCTION dbo.DataFromOtherDB()
RETURNS @Results TABLE ([SomeValue] INT)
AS
BEGIN
    INSERT INTO @Results ([SomeValue])
        SELECT [SomeValue]
        FROM   DatabaseB.dbo.LotsOfValues;

    RETURN;
END;
GO

GRANT SELECT ON dbo.[DataFromOtherDB] TO [RestrictedUser];
GO
---

USE [DatabaseB];

CREATE TABLE dbo.[LotsOfValues]
(
    [LotsOfValuesID] INT IDENTITY(1, 1) NOT NULL
        CONSTRAINT [PK_LotsOfValues] PRIMARY KEY,
    [SomeValue] INT
);

INSERT INTO dbo.[LotsOfValues] VALUES
    (1), (10), (100), (1000);
GO

---

USE [DatabaseA];

SELECT * FROM dbo.[DataFromOtherDB]();


EXECUTE AS LOGIN = 'RestrictedUser';

SELECT * FROM dbo.[DataFromOtherDB]();
/*
Msg 916, Level 14, State 1, Line XXXXX
The server principal "RestrictedUser" is not able to access
the database "DatabaseB" under the current security context.
*/

REVERT;

上面的所有步骤都重新创建了当前状况:用户有权访问DatabaseA,有权与DatabaseA中的对象进行交互,但是由于DatabaseA中的该对象访问了DatabaseB中的用户无法访问的内容而导致错误。

以下步骤设置了模块唱歌。它执行以下操作:

  1. 在DatabaseA中创建证书
  2. 用证书签署TVF
  3. 将证书(无私钥)复制到数据库B
  4. 从证书在DatabaseB中创建一个用户
  5. 授予SELECT权限表中DatabaseB的基于证书的用户

模块签名设置:

CREATE CERTIFICATE [AccessOtherDB]
    ENCRYPTION BY PASSWORD = 'SomePassword'
    WITH SUBJECT = 'Used for accessing other DB',
    EXPIRY_DATE = '2099-12-31';

ADD SIGNATURE
    TO dbo.[DataFromOtherDB]
    BY CERTIFICATE [AccessOtherDB]
    WITH PASSWORD = 'SomePassword';

---
DECLARE @CertificatePublicKey NVARCHAR(MAX) =
            CONVERT(NVARCHAR(MAX), CERTENCODED(CERT_ID(N'AccessOtherDB')), 1);

SELECT @CertificatePublicKey AS [Cert / PublicKey]; -- debug

EXEC (N'USE [DatabaseB];
CREATE CERTIFICATE [AccessOtherDB] FROM BINARY = ' + @CertificatePublicKey + N';');
---


EXEC (N'
USE [DatabaseB];
CREATE USER [AccessOtherDbUser] FROM CERTIFICATE [AccessOtherDB];

GRANT SELECT ON dbo.[LotsOfValues] TO [AccessOtherDbUser];
');

---



EXECUTE AS LOGIN = 'RestrictedUser';

SELECT * FROM dbo.[DataFromOtherDB]();
-- Success!!

SELECT * FROM [DatabaseB].[dbo].[LotsOfValues];
/*
Msg 916, Level 14, State 1, Line XXXXX
The server principal "RestrictedUser" is not able to access
the database "DatabaseB" under the current security context.
*/

REVERT;

如果出于某种原因需要通过视图进行访问,则只需创建一个视图即可从上面显示的TVF中进行选择。而且,在这种情况下,SELECT不访问没有需要被授予TVF,只能查看,这表现如下:

GO
CREATE VIEW dbo.[DataFromTVF]
AS
SELECT [SomeValue]
FROM   dbo.DataFromOtherDB();
GO

-- Remove direct access to the TVF as it is no longer needed:
REVOKE SELECT ON dbo.[DataFromOtherDB] FROM [RestrictedUser];

GRANT SELECT ON dbo.[DataFromTVF] TO [RestrictedUser];

现在进行测试:

EXECUTE AS LOGIN = 'RestrictedUser';


SELECT * FROM dbo.[DataFromOtherDB]();
/*
Msg 229, Level 14, State 5, Line XXXXX
The SELECT permission was denied on the object 'DataFromOtherDB',
database 'DatabaseA', schema 'dbo'.
*/


SELECT * FROM [OwnershipChaining].[dbo].[LotsOfValues];
/*
Msg 916, Level 14, State 1, Line XXXXX
The server principal "RestrictedUser" is not able to access
the database "DatabaseB" under the current security context.
*/


SELECT * FROM dbo.[DataFromTVF];
-- Success!!


REVERT;

有关模块签名的更多信息,请访问:https : //ModuleSigning.Info/


证书是否作为常规备份的一部分进行备份?还是将它们存储在其他位置,并且还需要备份文件系统?如果还原到可能使用不同密码等的较低环境,会发生什么?
克里斯·奥尔德里奇

@ChrisAldrich在此处显示的用法中,由于它完全保存在数据库中,因此已与数据库一起备份。如果使用,ALTER CERTIFICATE ... DROP PRIVATE KEY那么如果您没有先使用BACKUP CERTIFICATE将其备份到文件,则私钥将消失。但是,公钥仍在sys.certificates。而且公钥不需要密码。仅使用私钥对模块进行签名需要密码(服务器之间的密码是相同的,这与通过主密钥进行保护不同)。
所罗门·鲁兹基
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.