다른 데이터베이스의 계정이없는 다른 데이터베이스의 테이블을 기반으로 한 액세스 뷰


10

database2의 테이블을 기반으로 database1에서 뷰를 만들었습니다. SELECTdatabase1에만 액세스 할 수있는 사용자 에게 권한을 부여했습니다. 사용자는 database2에 계정이 없기 때문에이보기를 작동시킬 수 없습니다. 이 문제를 어떻게 해결할 수 있습니까? database2에서 계정을 만들고 싶지 않습니다.


1
@mustaccio 아니요, 상황이 모두 같은 데이터베이스에 있었기 때문에 다른 질문 / 답변과 중복되지 않습니다.이 질문은 데이터베이스 확장에 관한 것입니다. 기본적으로 허용되지 않습니다. 하나는 데이터베이스 간 소유권 체인을 가능하게해야 할 것이며, 이러한 좁은 요구를 충족시키기 위해서는 매우 큰 보안 허점이 있습니다.
Solomon Rutzky

1
@SolomonRutzky, 나는 DB_CHAINING을 "거대한 보안 구멍"이라고 부르지 않을 것입니다. sysadmin 역할 구성원 만 개체를 ​​만들 수있는 일반적인 프로덕션 환경에서는 문제가 아닙니다. 즉, 비 sysadmin 역할 구성원이 소유 한 스키마 이외의 스키마에 대한 제어 권한을 갖는 경우에는주의해서 사용해야합니다.
Dan Guzman

@ DanGuzman "신뢰, 모든 것은 항상 계획에 따라 갈 것"은 효과적인 전략이 아닙니다. 이 논리에 따르면 TRUSTWORTHY ON애플리케이션을로 로그인하거나 로그인 할 때 위험이 거의 없습니다 sa. DB 소유권 체인 TRUSTWORTHY은 주로 당시 유일한 솔루션으로 인해 존재합니다. 그러나 이제는 큰 위험 이 아니더라도 모듈 서명이 그렇게 어렵지 않기 때문에 DB Chaining은 불필요한 위험입니다. 그리고 DB 체인에 의존하고 동적 SQL을 사용 TRUSTWORTHY ON하는 경우이를 수정 하도록 설정 하는 반면 모듈 서명을 사용하면 손상되지 않습니다.
Solomon Rutzky

@ SolooloRutzky, 질문이 뷰 대신 모듈에 관한 것이면 모듈 서명을 제안했을 것입니다. 내 생각은 DB_CHAINING객체가 어쨌든 같은 데이터베이스에 있어야했을 때 데이터베이스 내 소유권 체인보다 더 위험하지 않다는 것입니다.
Dan Guzman

@DanGuzman 왜 "어쨌든 같은 데이터베이스에 객체가 있었어야합니까?" OP는 DB 액세스를 분리하기를 원하기 때문에 반대의 경우 만 표시했습니다. OP가 View를 사용하고 있기 때문에 Stored Procedure 대신 TVF를 제안했지만 View를 계속 사용하는 것이 최선의 방법입니다. 여기에서와 같이 변경이 필요한 경우 구조 및 / 또는 접근 방식을 수정하는 것이 일반적입니다. 아직도, 나는 선택적 래퍼보기를 내 대답에 추가했습니다. 그리고 "dbo"가 모든 것을 소유하는 것이 가장 일반적이라는 것을 감안할 때, DB_CHAINING매우 위험합니다.
Solomon Rutzky

답변:


9

이것은 모듈 서명을 사용하여 매우 안전한 방법으로 달성하기 쉽습니다. 이것은 DBA.StackExchange의 다음 두 가지 대답과 비슷합니다.

실행 계정, 데이터베이스 간 쿼리 및 모듈 서명을 사용한 저장 프로 시저 보안

교차 데이터베이스 인증서를 사용할 때 트리거의 권한

이 특정 질문의 차이점은 뷰를 다루고 뷰에 서명 할 수 없다는 것입니다. 따라서 뷰를 서명과 같이 액세스하고 액세스 할 수 있으므로 TVF (Multi-Statement Table-Valued Function)로 뷰를 변경해야합니다 SELECT.

다음 예제 코드는 로그인 / 사용자 "RestrictedUser"가 "DatabaseA"에만 액세스 할 수 있지만 "DatabaseB"에서 데이터를 가져올 수 있다는 점에서 질문에서 요청한 내용을 정확하게 수행하는 것을 보여줍니다. 이것은 하나의 TVF에서 선택 해야하며 서명되어 있기 때문에 가능합니다.

뷰를 계속 사용하면서 사용자에게 추가 권한을 부여 하지 않고이 유형의 데이터베이스 간 액세스를 수행 하려면 데이터베이스 간 소유권 체인을 활성화해야합니다. 두 데이터베이스 사이의 모든 객체에 대해 완전히 개방되어 있기 때문에 훨씬 안전하지 않습니다 (특정 객체 및 / 또는 사용자로 제한 할 수 없음). 모듈 서명을 사용하면이 TVF 하나만 DB 간 액세스 권한을 가질 수 있으며 (사용자 SELECT는 TVF 권한을 갖지 못하고) 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에서 선택하는보기를 간단히 만들 수 있습니다. 이러한 상황에서 아래에 설명 된 것처럼 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/를 참조하십시오.


인증서는 정기 백업의 일부로 백업됩니까? 아니면 다른 곳에 저장되어 있고 파일 시스템 백업도 필요합니까? 다른 암호 등을 사용할 수있는 낮은 환경으로 복원하면 어떻게됩니까?
Chris Aldrich

@ChrisAldrich 여기에 표시된 사용법에서는 데이터베이스가 완전히 데이터베이스 내에 유지되므로 DB와 함께 백업됩니다. 당신이 사용하는 경우 ALTER CERTIFICATE ... DROP PRIVATE KEY다음 먼저 사용하여 파일을 백업하지 않은 경우 개인 키는 사라질 것입니다 BACKUP 인증서를 . 그러나 공개 키는 여전히 sys.certificates. 그리고 공개 키에는 암호가 필요하지 않습니다. 개인 키를 사용하여 모듈에 서명하는 경우에만 암호가 필요합니다 (마스터 키를 통해 보호 할 때와 달리 서버간에 동일 함).
Solomon Rutzky
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.