Доступ к представлению на основе таблицы в другой базе данных без учета в этой другой базе данных

10

Я создал представление в database1 на основе таблиц в database2. Я дал SELECTразрешение пользователю, который имеет доступ только к базе данных1. Пользователь не может заставить это представление работать, потому что у него нет учетной записи в базе данных2. Как я могу решить эту проблему? Я не хочу создавать учетную запись в базе данных2.

Том
источник
1
@mustaccio Нет, это не дубликат этого другого вопроса / ответа, так как эта ситуация была в одной базе данных, и этот вопрос касается охвата баз данных. По умолчанию это не разрешено. Можно было бы включить цепочку владения несколькими базами данных, и это огромная дыра в безопасности, открывающаяся для такой узкой потребности.
Соломон Руцкий
1
@SolomonRutzky, я бы не назвал DB_CHAINING "огромной дырой в безопасности". В типичных производственных средах, где объекты могут создавать только члены роли sysadmin, это не проблема. Тем не менее, его следует использовать осторожно в тех случаях, когда члены роли, не являющиеся системными администраторами, имеют разрешения на управление схемами, отличными от тех, которыми они владеют.
Дан Гусман
@DanGuzman «Поверь мне, все всегда будет идти по плану» - неэффективная стратегия. По этой логике практически нет риска установки TRUSTWORTHY ONили входа приложения в систему как sa. Владение БД цепочкой и TRUSTWORTHYсуществует в основном благодаря тому, что является единственным решением на тот момент. Но теперь, даже если и не огромный риск, DB Chaining, безусловно, является ненужным риском, поскольку подписывание модулей не так сложно. И если кто-то полагается на цепочку БД, а затем использует динамический SQL, они с большей вероятностью TRUSTWORTHY ONрешат это исправить, тогда как при подписании модуля это не сломалось бы.
Соломон Руцкий
@SolomonRutzky, я бы предложил подписать модуль, если бы вопрос был о модуле, а не о представлении. Я думаю, что DB_CHAININGэто не более рискованно, чем цепочка владения внутри базы данных, когда объекты все равно должны были находиться в одной базе данных.
Дан Гузман
@DanGuzman Зачем считать, что «объекты должны были быть в одной базе данных?» OP только указал противоположное, так как они хотят разделить доступ к БД. Именно из-за того, что OP использует View, я предложил TVF вместо хранимой процедуры, но это не означает, что продолжение использования View - лучший способ действий. Распространено предлагать изменение структуры и / или подхода, когда это имеет смысл, как здесь. Тем не менее, я добавил опциональную оболочку View в свой ответ. И, учитывая, что «dbo» чаще всего владеет всем, да, DB_CHAININGэто довольно рискованно.
Соломон Руцкий

Ответы:

9

Это легко сделать очень безопасным способом, используя подпись модулей. Это будет похоже на следующие два моих ответа, также здесь, на DBA.StackExchange, в которых приведены примеры того, как это сделать:

Безопасность хранимых процедур с помощью execute as, запросов к базе данных и подписи модуля

Разрешения в триггерах при использовании кросс-сертификатов базы данных

Разница для этого конкретного вопроса заключается в том, что он имеет дело с представлением, и представления не могут быть подписаны. Таким образом, вам нужно будет изменить представление в табличную функцию с множеством операторов (TVF), так как они могут быть подписаны и доступны так же, как представление (ну, для SELECTдоступа).

В следующем примере кода показано выполнение именно того, что запрашивается в вопросе, в том, что «Ограниченный пользователь» для входа / пользователя имеет доступ только к «DatabaseA» и все же может получать данные из «DatabaseB». Это работает только путем выбора из этого одного TVF , и только потому, что он подписан.

Для реализации этого типа доступа к нескольким базам данных при использовании представления и без предоставления Пользователю каких-либо дополнительных разрешений потребуется включение цепочки владения несколькими базами данных. Это гораздо менее безопасно, потому что он полностью открыт для всех объектов между обеими базами данных (он не может быть ограничен определенными объектами и / или пользователями). Подписание модуля позволяет только этому одному TVF иметь доступ между БД (у пользователя нет разрешения, у TVF есть), а у пользователей, которые не могут SELECTиз TVF вообще не иметь доступа к базе данных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. создает сертификат в базе данных
  2. Подписывает TVF с сертификатом
  3. Копирует сертификат (без закрытого ключа) в базу данных B
  4. Создает пользователя в базе данныхB из сертификата
  5. Предоставляет SELECTразрешение на Таблицу в базе данныхB Пользователю на основе сертификатов

Настройка подписи модуля:

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. И открытый ключ не нуждается в пароле. Только для использования закрытого ключа для подписи модуля требуется пароль (который одинаков для всех серверов, в отличие от защиты с помощью мастер-ключа).
Соломон Руцкий