วิธีนี้ง่ายต่อการบรรลุผลอย่างปลอดภัยโดยใช้การเซ็นชื่อโมดูล นี่จะคล้ายกับสองคำตอบของฉันต่อไปนี้ที่ DBA.StackExchange ที่ให้ตัวอย่างของการทำสิ่งนี้:
ความปลอดภัยของโพรซีเดอร์ที่เก็บไว้ด้วย execute เป็น, ข้ามแบบสอบถามฐานข้อมูลและเซ็นชื่อโมดูล
สิทธิ์ในทริกเกอร์เมื่อใช้ใบรับรองฐานข้อมูลข้าม
ข้อแตกต่างสำหรับคำถามนี้คือเกี่ยวข้องกับมุมมองและไม่สามารถลงชื่อเข้าใช้มุมมองได้ ดังนั้นคุณจะต้องเปลี่ยนมุมมองเป็นฟังก์ชั่น Table-Valued Function แบบหลายคำสั่ง (TVF) เนื่องจากสามารถลงชื่อและสามารถเข้าถึงได้เช่นเดียวกับมุมมอง (ดีสำหรับSELECT
การเข้าถึง)
ตัวอย่างรหัสต่อไปนี้แสดงให้เห็นว่าสิ่งที่ถูกร้องขอในคำถามในการเข้าสู่ระบบ / ผู้ใช้ "RestrictedUser" เท่านั้นที่สามารถเข้าถึง "DatabaseA" และยังสามารถรับข้อมูลจาก "DatabaseB" ได้ สิ่งนี้ใช้งานได้โดยเลือกจาก TVF อันนี้เท่านั้นและเนื่องจากการลงชื่อเท่านั้น
สำเร็จการเข้าถึงข้ามฐานข้อมูลประเภทนี้ในขณะที่ยังใช้มุมมองและไม่ให้สิทธิ์เพิ่มเติมแก่ผู้ใช้จะต้องเปิดใช้งานการผูกมัดการเป็นเจ้าของฐานข้อมูลข้ามฐานข้อมูล มีความปลอดภัยน้อยกว่ามากเนื่องจากเป็นวัตถุแบบเปิดทั้งหมดสำหรับฐานข้อมูลทั้งสอง (ไม่สามารถ จำกัด เฉพาะบางวัตถุและ / หรือผู้ใช้) การเซ็นชื่อโมดูลอนุญาตให้ 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 เข้าถึงบางสิ่งใน DatabaseA ซึ่งผู้ใช้ไม่มีการเข้าถึงใด ๆ
ขั้นตอนด้านล่างตั้งค่าการร้องเพลงของโมดูล มันทำต่อไปนี้:
- สร้างใบรับรองใน DatabaseA
- ลงชื่อ TVF ด้วยใบรับรอง
- คัดลอกใบรับรอง (ไม่มีรหัสส่วนตัว) ไปยังฐานข้อมูล B
- สร้างผู้ใช้ในฐานข้อมูล B จากใบรับรอง
- แกรนต์
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/