他のデータベースのアカウントなしで、他のデータベースのテーブルに基づいてビューにアクセスする


10

database2のテーブルに基づいて、database1にビューを作成しました。SELECTdatabase1にのみアクセスできるユーザーに許可を与えました。データベース2にアカウントがないため、ユーザーはこのビューを機能させることができません。この問題を解決するにはどうすればよいですか?database2にアカウントを作成したくありません。


1
@mustaccioいいえ、その状況はすべて同じデータベース内にあったため、これは他の質問/回答の複製ではありません。この質問はデータベースのスパンに関するものです。デフォルトでは許可されていません。データベース間の所有権の連鎖を有効にする必要があります。これは、そのような狭い必要性に対して開ける巨大なセキュリティホールです。
ソロモンルツキー

1
@SolomonRutzky、私はDB_CHAININGを「巨大なセキュリティホール」とは呼びません。sysadminロールのメンバーだけがオブジェクトを作成できる一般的な本番環境では、これは問題ではありません。ただし、sysadmin以外の役割のメンバーが、自分が所有しているスキーマ以外のスキーマに対する制御権限を持っている場合は、注意して使用する必要があります。
Dan Guzman

@DanGuzman「信頼してください、すべては常に計画どおりに進みます」は効果的な戦略ではありません。そのロジックによりTRUSTWORTHY ON、アプリケーションをとしてログインしたり設定したりするリスクはほとんどありませんsa。DB所有権の連鎖は、TRUSTWORTHY主に当時唯一のソリューションであるために存在します。しかし、今では、大きなリスクでなくても、モジュール署名はそれほど難しくないので、DBチェーンは確かに不必要なリスクです。また、DBチェーンに依存してから動的SQLを使用TRUSTWORTHY ONする場合、修正するように設定する可能性が高くなりますが、モジュール署名を使用すると、問題が発生することはありません。
ソロモンルツキー

@SolomonRutzky、質問がビューではなくモジュールに関するものである場合、モジュール署名を提案したでしょう。DB_CHAININGとにかく、オブジェクトが同じデータベースにあるべきだった場合、データベース内の所有権の連鎖と同じくらいリスクが高いとは思いません。
Dan Guzman、2017

@DanGuzmanなぜ「オブジェクトはとにかく同じデータベースにあるべきだった」と仮定するのですか?OPはDBアクセスを分離したままにしたいので、反対を示しただけです。OPがビューを使用していることが、ストアドプロシージャの代わりにTVFを提案した理由ですが、それはビューの使用を継続することが最善策であることを意味しません。ここでそうであるように、意味をなす場合は構造やアプローチを変更することを提案するのが一般的です。それでも、オプションのラッパービューを回答に追加しました。そして、「dbo」がすべてを所有することが最も一般的であることを考えると、はい、DB_CHAININGかなり危険です。
ソロモンルツキー2017

回答:


9

これは、モジュール署名を使用して非常に安全な方法で簡単に実行できます。これは、次の2つの私の答えと似ていますが、ここでもDBA.StackExchangeで、これを行う例を示しています。

実行方法、クロスデータベースクエリ、モジュール署名によるストアドプロシージャのセキュリティ

クロスデータベース証明書を使用する場合のトリガーの権限

この特定の質問の違いは、ビューを処理することと、ビューに署名できないことです。したがって、ビューをマルチステートメントのテーブル値関数(TVF)に変更する必要があります。署名付きで、ビューと同じようにアクセスできます(SELECTアクセス用)。

次のコード例は、ログイン/ユーザー「RestrictedUser」が「DatabaseA」にのみアクセスでき、「DatabaseB」からデータを取得できるという点で、質問で要求されていることを正確に実行することを示しています。これは、この1つのTVFから選択することによってのみ機能し、署名されているためです。

ビューを使用しながら、ユーザーに追加のアクセス許可を与えに、このタイプのクロスデータベースアクセスを実現するには、クロスデータベース所有権の連鎖を有効にする必要があります。両方のデータベース間のすべてのオブジェクトに対して完全に制限がないため、安全性ははるかに低くなります(特定のオブジェクトやユーザーに制限することはできません)。モジュール署名により、この1つのTVFだけがクロスDBアクセスを許可され(ユーザーには権限がなく、TVFは許可されます)、SELECTTVFからアクセスできないユーザーは「データベースB」にアクセスできません。

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から選択するビューを作成するだけです。そして、そのような状況では、以下に示すように、TVF SELECTへのアクセスを許可する必要はなく、ビューへのアクセスのみを許可する必要があります。

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ここに示す使用法では、データベース内に完全に保持されているため、DBでバックアップされます。使用するALTER CERTIFICATE ... DROP PRIVATE KEY場合、BACKUP CERTIFICATEを使用して最初にファイルにバックアップしないと、秘密鍵は失われます。しかし、公開鍵はまだ残っていsys.certificatesます。また、公開鍵にはパスワードは必要ありません。秘密鍵を使用してモジュールに署名する場合にのみパスワードが必要です(マスターキーで保護する場合とは異なり、サーバー間で同じです)。
ソロモンルツキー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.