允許非特權使用者使特權程式碼執行
語境:
我們的 SQL 伺服器是用於教學的,我們需要能夠根據需要和實時為學生自動創建數據庫。我們還需要學生能夠刪除他們創建的數據庫。學生不能被授予管理員權限,或任何其他可能允許他們破壞伺服器的訪問級別。
在我們的舊伺服器上,我們有一個簡單但有效的解決方案,它基於一個擴展的儲存過程:有一個“管理數據庫”,它的工作是跟踪和操作學生的數據庫,還有一個 SQL Server 代理工作,它一直在執行。擴展儲存過程允許作業進入睡眠狀態並被喚醒,此時它創建或刪除表中條目指示的數據庫,並遵循各種業務規則,然後再次進入睡眠狀態。(如有必要,我可以對此進行擴展,但希望您能理解。)
我們已停用舊伺服器,因為它正在執行 SQL Server 2008 R2,並將為即將到來的執行 SQL Server 2019 的三個月建構一個新伺服器。從我發現的文件中,不推薦使用擴展儲存過程,但仍然支持,所以在原則我可以重用現有的解決方案。但是,如果可能的話,我想做一些更理智的事情。
問題:
我想我需要問的是如何最好地允許非特權使用者導致儲存過程,該儲存過程在足夠特權的上下文中執行以動態創建和刪除數據庫,執行或失敗,從睡眠中喚醒.
但是,我很樂意收到針對我的潛在問題的其他可能解決方案的建議,即允許非特權使用者根據業務規則按需創建和刪除數據庫。(例如,我們要求數據庫以學生的使用者名作為前綴。我們還需要在創建數據庫時配置數據庫安全性,以便學生可以訪問它。當然學生應該只能刪除自己的數據庫,而不是其他人的。)
如果我沒記錯(並且基於一些快速研究)觸發器等將不起作用,因為它們在觸發它們的使用者的上下文中執行,例如,請參閱這篇文章。 但也許一個簽名的儲存過程會起作用?我在這裡尋找最簡單、最明智的選擇,並考慮到誰最終在我之後照顧這台伺服器,並尋找可以理解和可維護的解決方案。
服務端可以完全用 SQL 實現的解決方案是首選,但這不是絕對要求。
針對評論的附加說明:
- 學生通過 Windows 登錄進行身份驗證,並根據 Windows 組的成員資格授予訪問權限。
- 在舊伺服器上,我們沒有讓學生 dbo 訪問他們自己的數據庫,因為我們不確定安全隱患。我們確實給了他們 db_ddladmin、db_datareader 和 db_datawriter 角色。
也許簽名的儲存過程會起作用?我在這裡尋找最簡單、最明智的選擇,並考慮到誰最終在我之後照顧這台伺服器,並尋找可以理解和可維護的解決方案。
是的。一個簽名的儲存過程絕對可以工作,而且工作得很好。隨著個人需求的發展,“最簡單”並不總是與“最健全”重疊;人們經常選擇最簡單的方法,放棄了太多的理智(這是可以理解的,因為根據定義,最簡單的方法是最容易理解的,而且“更理智”的方法顯然不是更理智(至少不是第一的))。這就是模組簽名的用武之地。雖然不是最簡單的方法,但它是迄今為止最明智的,考慮到所有的事情。不幸的是,它也沒有被很好地理解,因此似乎比實際情況更令人困惑/困難。
一般概念是:
創建創建學生數據庫的儲存過程(在“管理”數據庫中):
為項目名稱設置一個參數(記住:最大 DB 名稱可以是 128 個字元,並且您需要為學生登錄名稱保留一些作為 DB 名稱的前綴,因此取決於獲得的時間長短,大小這個適當地,最多 20 - 30 個字元,因此
NVARCHAR(20ish)
)使用所需的命名約定(包括項目名稱)創建數據庫。您可以從各種系統變數和內置函式中獲取他們的登錄名,但這
ORIGINAL_LOGIN()
可能是最好的選擇。您可能需要進行簡單的字元串操作,因為名稱將以機器/域名為前綴。
USE
新數據庫為該學生的帳戶創建一個使用者:
DECLARE @User NVARCHAR(258) = ORIGINAL_LOGIN(); SET @User = QUOTENAME(manipulated_@User); EXEC (N'CREATE USER ' + @User);
為學生帳戶添加權限/角色:
EC (N'ALTER ROLE [db_datareader] ADD MEMBER ' + @User); .
2. 創建刪除學生數據庫的儲存過程(在“管理”數據庫中): 為項目名稱設置一個參數(記住:最大 DB 名稱可以是 128 個字元,並且您需要為學生登錄名稱保留一些作為 DB 名稱的前綴,因此取決於獲得的時間長短,大小這個適當地,最多 20 - 30 個字元,因此`NVARCHAR(20ish)`) 刪除具有所需命名約定(包括項目名稱)的數據庫。1. 將`EXECUTE`這些模組授予執行這些操作所需的任何使用者和/或角色(可以是“學生”AD 組,或`[public]`在[聊天室中註明](https://chat.stackexchange.com/rooms/101816/discussion-between-solomon-rutzky-and-harry-johnston) 3. 創建證書(在“管理”數據庫中) 4. 使用該證書籤署儲存過程(使用`ADD SIGNATURE`) 5. 將證書複製到`[master]`數據庫(即`[master]`使用用於簽署儲存過程的證書的公鑰創建證書)。 6. 從復製到的證書創建登錄`[master]` 7. 授予該基於證書的登錄所需的任何實例級權限(包括將其添加到實例級角色)。 有關一些範例,請參閱: * [如何維護跨域的數據庫所有權恢復?](https://dba.stackexchange.com/a/251918/30859) * [無需將高級權限授予任何人即可安全輕鬆地使用高級權限:伺服器級](https://sqlquantumleap.com/2018/02/15/safely-and-easily-use-high-level-permissions-without-granting-them-to-anyone-server-level/)