跨數據庫視圖 - 在目前安全上下文下無法訪問數據庫
我們有兩個數據庫,
Adb
和Bdb
. 在Bdb
中,我們創建一個引用另一個視圖的視圖,如下所示Adb
:CREATE VIEW Bdb.dbo.Bview AS SELECT * FROM Adb.dbo.Aview
我們有一個 SQL Authenticated
Blogin
,映射到Buser
,都在Adb
和Bdb
上,至少db_datareader
在兩者上都有角色。以下不起作用:
USE Bdb; EXECUTE AS USER = 'Buser'; SELECT * FROM Bdb.dbo.Bview; SELECT * FROM Adb.dbo.Aview;
兩種選擇都會引發以下錯誤:
Msg 916, Level 14, State 1, Line 4 The server principal "Buser" is not able to access the database "Adb" under the current security context.
但是,這有效:
USE Adb; EXECUTE AS USER = 'Buser'; SELECT * FROM Adb.dbo.Aview; SELECT * FROM Bdb.dbo.Bview;
我注意到,當我第一次
USE Bdb
切換到時Buser
,我看不到任何其他數據庫:USE Bdb; EXECUTE AS USER = 'Buser'; SELECT * FROM sys.databases; -- only master, tempdb and Bdb is shown
但是,當我
USE Adb
第一次看到它們時,我看到了所有這些,即使是那些沒有Buser
並且不能被它訪問的:USE Adb; EXECUTE AS USER = 'Buser'; SELECT * FROM sys.databases; -- all DBs on the server are shown
什麼可能導致此問題?我應該檢查什麼?
首先要做的事情:不要啟用可信!絕對沒有理由打開這麼大的安全漏洞。(注意:
msdb
已TRUSTWORTHY
啟用,這很好,因為它是 Microsoft 提供的數據庫;使用者創建的數據庫永遠不需要TRUSTWORTHY
啟用)現在,如果這在模擬使用者而不是登錄時有效,那是因為您的
[Adb]
數據庫已啟用為TRUSTWORTHY ON
,這將刪除使用數據庫級模擬時存在的預設隔離區。您可以通過執行以下命令來看到這一點:SELECT db.is_trustworthy_on, * FROM sys.databases db WHERE db.[name] IN (N'Adb', N'Bdb');
假設
Adb
是啟用TRUSTWORTHY
而Bdb
沒有啟用的情況,那麼還是請不要啟用TRUSTWORTHY
forBdb
。最好禁用TRUSTWORTHY
forAdb
並使用模組簽名來完成此操作:ALTER DATABASE [Adb] SET TRUSTWORTHY OFF;
有關通過模組簽名進行此跨數據庫訪問的範例,請參閱我的以下答案(在 DBA.SE 上):
基於另一個數據庫中的表的訪問視圖,而沒有該其他數據庫中的帳戶
有關為什麼應該使用模組簽名而不是 TRUSTWORTHY(甚至是跨數據庫所有權連結)的更多資訊,請參閱我的以下文章:
有關模組簽名的更多資訊,請參閱:
正如@Nic 在對該問題的評論中提到的那樣,最好在測試時使用
EXECUTE AS LOGIN
而不是使用。EXECUTE AS USER
登錄位於伺服器級別,並且可以訪問已為該登錄創建使用者的數據庫。這就像以該帳戶登錄 SQL Server 一樣。差異的原因在 Microsoft 文件頁面中說明了通過使用 EXECUTE AS 擴展數據庫模擬
了解模擬範圍
…
但是,當使用 EXECUTE AS USER 語句或在數據庫範圍的模組中使用 EXECUTE AS 子句模擬主體時,預設情況下模擬的範圍僅限於數據庫。這意味著對數據庫範圍之外的對象的引用將返回錯誤。
此外,“Extending Database Impersonation by Using EXECUTE AS”MSDN 頁面(上面連結)上有很多很好的資訊,解釋了身份驗證器和這些規則背後的推理。
鑑於這兩個數據庫是供應商提供的(在我送出此答案後添加了資訊),那麼最好只切換到數據庫
EXECUTE AS LOGIN
而不對數據庫進行任何更改(用於模組簽名)。