มุมมองการเข้าถึงตามตารางในฐานข้อมูลอื่นที่ไม่มีบัญชีในฐานข้อมูลอื่นนั้น


11

ฉันสร้างมุมมองในฐานข้อมูล 1 ตามตารางในฐานข้อมูล 2 ฉันให้SELECTสิทธิ์แก่ผู้ใช้ที่เข้าถึงได้เฉพาะฐานข้อมูล 1 ผู้ใช้ไม่สามารถรับมุมมองนี้ให้ทำงานได้เนื่องจากเขาไม่มีบัญชีในฐานข้อมูล 2 ฉันจะแก้ปัญหานี้ได้อย่างไร ฉันไม่ต้องการสร้างบัญชีในฐานข้อมูล 2


1
@mustaccio ไม่ไม่เหมือนกันกับคำถาม / คำตอบอื่น ๆ เนื่องจากสถานการณ์นั้นอยู่ในฐานข้อมูลเดียวกันและคำถามนี้เกี่ยวกับการขยายฐานข้อมูล โดยค่าเริ่มต้นที่ไม่ได้รับอนุญาต หนึ่งจะต้องเปิดใช้งานการผูกมัดฐานข้อมูลข้ามฐานข้อมูลและนั่นเป็นช่องโหว่ความปลอดภัยขนาดใหญ่เพื่อเปิดสำหรับความต้องการแคบ ๆ
โซโลมอน Rutzky

1
@ SolomonRutzky ฉันจะไม่เรียก DB_CHAINING "ช่องโหว่ขนาดใหญ่" ในสภาพแวดล้อมการผลิตทั่วไปที่มีเพียงสมาชิกบทบาทดูแลระบบเท่านั้นที่สามารถสร้างวัตถุได้มันไม่ใช่ปัญหา ที่กล่าวว่าควรใช้อย่างระมัดระวังในกรณีที่สมาชิกบทบาทที่ไม่ใช่ผู้ดูแลระบบมีสิทธิ์ควบคุมสคีมานอกเหนือจากที่พวกเขาเป็นเจ้าของ
Dan Guzman

@DanGuzman "เชื่อฉันทุกอย่างจะเป็นไปตามแผนเสมอ" ไม่ใช่กลยุทธ์ที่มีประสิทธิภาพ โดยตรรกะที่มีเกือบไม่มีความเสี่ยงในการตั้งค่าหรือมีบันทึกของโปรแกรมประยุกต์ในการเป็นTRUSTWORTHY ON saการเป็นเจ้าของฐานข้อมูลการผูกมัดและTRUSTWORTHYมีอยู่ส่วนใหญ่เนื่องจากเป็นทางออกเดียวในเวลา แต่ตอนนี้แม้ว่าจะไม่ได้มีความเสี่ยงมาก แต่ DB Chaining ก็เป็นความเสี่ยงที่ไม่จำเป็นเนื่องจากการเซ็นชื่อของโมดูลนั้นไม่ยาก และหากมีใครอาศัยการผูกมัดฐานข้อมูลจากนั้นใช้ Dynamic SQL พวกเขาก็มีแนวโน้มที่TRUSTWORTHY ONจะแก้ไขได้ในขณะที่การลงนามโมดูลจะไม่เสีย
โซโลมอน Rutzky

@SolomonRutzky ฉันจะแนะนำให้เซ็นชื่อโมดูลหากคำถามเกี่ยวกับโมดูลแทนที่จะเป็นมุมมอง ความคิดของฉันDB_CHAININGคือไม่มีความเสี่ยงมากกว่าการผูกมัดฐานข้อมูลภายในเมื่อวัตถุควรอยู่ในฐานข้อมูลเดียวกันอยู่แล้ว
Dan Guzman

@DanGuzman ทำไมคิดว่า "วัตถุควรอยู่ในฐานข้อมูลเดียวกันอยู่แล้ว"? OP ได้ระบุสิ่งที่ตรงกันข้ามเนื่องจากต้องการแยกการเข้าถึงฐานข้อมูลออก การที่ OP ใช้มุมมองคือเหตุผลที่ฉันแนะนำ TVF แทนที่จะเป็น Stored Procedure แต่นั่นไม่ได้หมายความว่าการใช้ View เป็นวิธีที่ดีที่สุด มันเป็นเรื่องธรรมดาที่จะแนะนำการปรับเปลี่ยนโครงสร้างและ / หรือวิธีการเมื่อมันเหมาะสมที่จะทำเช่นกรณีที่นี่ ถึงกระนั้นฉันได้เพิ่มมุมมองตัวเลือกเสริมลงในคำตอบของฉัน และเนื่องจากว่ามันเป็นเรื่องธรรมดาที่สุดสำหรับ "dbo" ที่จะเป็นเจ้าของทุกอย่างใช่DB_CHAININGมีความเสี่ยงมาก
โซโลมอน Rutzky

คำตอบ:


9

วิธีนี้ง่ายต่อการบรรลุผลอย่างปลอดภัยโดยใช้การเซ็นชื่อโมดูล นี่จะคล้ายกับสองคำตอบของฉันต่อไปนี้ที่ 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 ซึ่งผู้ใช้ไม่มีการเข้าถึงใด ๆ

ขั้นตอนด้านล่างตั้งค่าการร้องเพลงของโมดูล มันทำต่อไปนี้:

  1. สร้างใบรับรองใน DatabaseA
  2. ลงชื่อ TVF ด้วยใบรับรอง
  3. คัดลอกใบรับรอง (ไม่มีรหัสส่วนตัว) ไปยังฐานข้อมูล B
  4. สร้างผู้ใช้ในฐานข้อมูล B จากใบรับรอง
  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/


certs ถูกสำรองไว้เป็นส่วนหนึ่งของการสำรองข้อมูลปกติหรือไม่ หรือพวกเขาถูกเก็บไว้ที่อื่นและต้องการสำรองระบบไฟล์เช่นกัน? และจะเกิดอะไรขึ้นถ้าคุณกู้คืนสภาพแวดล้อมที่ต่ำกว่าซึ่งอาจใช้รหัสผ่านที่แตกต่างกัน ฯลฯ
Chris Aldrich

@ChrisAldrich ในการใช้งานที่แสดงที่นี่มันถูกสำรองไว้กับ DB เนื่องจากมันถูกเก็บไว้ภายในฐานข้อมูลทั้งหมด ถ้าคุณใช้ALTER CERTIFICATE ... DROP PRIVATE KEYแล้วคีย์ส่วนตัวจะหายไปถ้าคุณไม่ได้เป็นครั้งแรกกลับขึ้นไปยังแฟ้มโดยใช้ใบรับรองการสำรองข้อมูล sys.certificatesแต่คีย์สาธารณะยังคงอยู่ใน และรหัสสาธารณะไม่จำเป็นต้องใช้รหัสผ่าน การใช้ไพรเวตคีย์ในการเซ็นชื่อโมดูลต้องใช้รหัสผ่านเท่านั้น (ซึ่งเหมือนกันในเซิร์ฟเวอร์ต่างจากเมื่อปกป้องผ่านมาสเตอร์คีย์)
โซโลมอน Rutzky
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.