在保密你的伺服器和數據,防備當前複雜的攻擊,SQL Server有你需要的一切。但在你能有效使用這些安全功能前,你需要理解你面對的威脅和一些基本的安全概念。這篇文章提供了基礎,因此你可以對SQL Server里的安全功能充分利用,不用在面對特定威脅,不能保護你數據的功能上浪費時間。 從讓人眼花繚亂的 ...
在保密你的伺服器和數據,防備當前複雜的攻擊,SQL Server有你需要的一切。但在你能有效使用這些安全功能前,你需要理解你面對的威脅和一些基本的安全概念。這篇文章提供了基礎,因此你可以對SQL Server里的安全功能充分利用,不用在面對特定威脅,不能保護你數據的功能上浪費時間。
從讓人眼花繚亂的客戶端使用連接,通過到處分佈的網路,尤其是互聯網,關係資料庫在各種應用程式里廣泛使用。這使數據對任何人,在任何地方都可訪問。資料庫可以保存人類知識的很大部分,包括高度敏感的個人信息和讓國際商務工作的關鍵數據。
對於想要偷取數據或通過篡改數據來傷害數據的擁有者的 人來說,這些功能使資料庫成為有吸引力的目標。確保你的數據安全是SQL Server配置和使用它來保存數據的程式的重要部分。這個系列會探尋SQL Server 2012安全的基本,這樣的話你可以保護你的數據和伺服器資源,按你需要的安全等級來保護數據,免受這些威脅對你數據的影響。大部分信息對SQL Server的早期版本也適用,回到SQL Server 2005也可以,因為那是微軟在產品里徹底檢查安全的時候。但我也會談論只在SQL Server 2012和後續版本里才有的功能。
大部分時間,你只要關註只有一個所有者的,在一個獨立資料庫里的數據和對象訪問安全。但有時候你需要接觸到外面的資料庫從多個資料庫範文數據和對象,它引起一些安全問題,增加了數據訪問的複雜性。在這篇文章里,你會學習跨資料庫所有權鏈接,這樣的話,你可以接觸到跨資料庫邊界的安全。
所有權鏈接
大部分時間,你都很可能創建引用其它對象的資料庫,所有對象都包含在同個資料庫里。例子包括,在同個資料庫里訪問表的存儲過程,在同個資料庫里把錶鏈接一起的視圖等等。但是有時候,你會需要創建越過資料庫邊界的訪問其它對象的對象。對於大部分,對於跨資料庫範文的安全規則都是一致的,只要在同個資料庫里。訪問的用戶需要在它們直接訪問的對象上有必要的許可,連續的所有權鏈接允許SQL Server縮短許可檢查等等。畢竟,SQL Server不能放鬆警惕,不管對象放在哪裡!在一個資料庫里,所有權鏈接簡化安全管理,同樣也適用於跨資料庫。
你是否在一個資料庫里還是跨過資料庫邊界,所有權鏈接如何工作的基本都是一樣的。所有的資料庫對象有個擁有者,所有者控制在它所有的對象上誰有許可。訪問其它對象的對象——例如在SELECT語句里連接多個表的存儲過程——構成一個所有權鏈接,它是連續的,只要單個所有者擁有所有涉及的對象。
在最高層對象上擁有許可的用戶的結果——一個存儲過程或視圖,例如——訪問其它對象的用戶不需要在潛在對象上有許可,只要這是一個連續的所有權鏈接。SQL Server在這樣的對象上,一旦驗證在最高層對象擁有許可,就停止檢查許可。這個架構給所有者在潛在對象的訪問,更多更好的控制,因為用戶只需要在它們直接訪問的對象上有許可。
提示:
理解所有權鏈接只適用於對象許可非常重要,例如SELECT,UPDATE和EXECUTE的操作。SQL Server總在數據定義語句上檢查許可,因為這些許可只適用於語句而不是對象。
跨資料庫所有權鏈接
跨資料庫所有權鏈接是所有權鏈接的延伸,所有的對象——包括用戶直接訪問的對象和潛在引用的對象——都在一個資料庫里。跨資料庫所有權鏈接的唯一區別是跨資料庫邊界。因此你可以在一個資料庫里有個在多個資料庫里把數據連接一起的視圖。或在多個資料庫里訪問對象的存儲過程。在這些情況下,用戶直接訪問的源對象取決於在另一個資料庫里包含的對象。
所有權鏈接的兩種類型直接的唯一重要區別是訪問資料庫,對象所有者的主體。資料庫用戶是在單個資料庫里完全包含的主體。即使多個資料庫每個有同樣的名稱,它們是獨立的,不同的主體,因此不能在連續的所有權鏈接里參與,除非所有這些用戶映射到同個資料庫級別的登錄。因此它是相關所有者的登錄,不是資料庫用戶。那就是關鍵概念:在連續所有權鏈接里對象的公共所有者是伺服器級別的主體,而不是資料庫級別的主體。
在內部,SQL Server通過它們的安全ID(SID)而不是用戶名來標識對象所有者。在單個資料庫里,單個用戶擁有的所有對象有一個SID ,作為所有者,因為在資料庫里只有一個用戶有那個名稱。但跨數據,SID是在伺服器級別上的終極登錄。在不同的資料庫里不同的用戶可以關聯不同登錄,因此會有不同的SID。這是用戶和登錄相比,很可能是一個最容易混淆的方面,因此這點你要確定清楚。
連續的跨資料庫所有權鏈接需要對象所有者的全部——源對象和所有引用的對象——用同樣的SID映射到同個登錄。
探尋跨資料庫所有權鏈接
這篇文章的代碼演示瞭如何使用跨資料庫所有權鏈接,並探尋它的特點。代碼通過在伺服器級別創建名為SharedLogin的登錄開始,如代碼7.1所示。接下來代碼使用這個作為用於在所有權鏈接里對象的共用所有者。
1 USE master; 2 GO 3 4 IF SUSER_SID('SharedLogin') IS NOT NULL DROP LOGIN SharedLogin; 5 CREATE LOGIN SharedLogin WITH password = 'Y&2!@37z#F!l1zB'; 6 GO
代碼7.1:創建會是對象所有者的SharedLogin登錄的代碼
在跨資料庫所有權鏈接里我們要涉及到兩個資料庫,因此接下來的代碼會創建它們。包含用戶直接訪問對象的資料庫名為SourceDB,引用對象的資料庫會是ChainedDB。ChainedDB包含一個dbo.AlaskaCity表,包含阿拉斯加三個最大城市的人口的一些數據。代碼7.2創建ChainedDB和它的AlaskaCity表,在表裡插入一些數據,用2010的人口調查數據。
1 IF DB_ID('ChainedDB') IS NOT NULL DROP DATABASE ChainedDB; 2 CREATE DATABASE ChainedDB; 3 GO 4 USE ChainedDB; 5 GO 6 7 -- Create a table for access from another database 8 CREATE TABLE dbo.AlaskaCity 9 ( 10 AlaskaCityID INT NOT NULL IDENTITY(1, 1), 11 CityName NVARCHAR(20) NOT NULL, 12 Population INT NOT NULL 13 CONSTRAINT PK_AlaskaCity PRIMARY KEY (AlaskaCityID) 14 ); 15 GO 16 17 INSERT INTO dbo.AlaskaCity (CityName, Population) 18 VALUES ('Fairbanks', 31535), ('Anchorage', 291826), ('Juneau', 31275); 19 GO
代碼7.2:創建ChainedDB資料庫和有插入樣本數據的AlaskaCity表的代碼
接下來的代碼創建SourceDB資料庫,包含一個用戶在ChainedDB資料庫里,從AlaskaCity直接訪問,獲取數據的視圖。如代碼7.3所示,包含一個SELECT語句來測試一切正常。如果你以sysadmin登錄的話,這一切都會正常,因為在SQL Server實例里你有所有對象的完整訪問,有用所有創建的對象,目前是dbo,你應該可以看到阿拉斯加的人口數據。以sysadmin運行是很方便,但對生產使用並不安全,通常用戶訪問代碼不會有所有對象的成員資格。
1 IF DB_ID('SourceDB') IS NOT NULL DROP DATABASE SourceDB; 2 CREATE DATABASE SourceDB; 3 GO 4 USE SourceDB; 5 GO 6 7 -- Create a view that accesses ChainedDB.dbo.AlaskaCity 8 CREATE VIEW dbo.AlaskaCitiesView AS 9 SELECT * FROM ChainedDB.dbo.AlaskaCity; 10 GO 11 12 SELECT * FROM dbo.AlaskaCitiesView ORDER BY Population DESC;
代碼7.3:創建SourceDB資料庫和在ChainedDB資料庫里訪問AlaskaCity表的視圖的代碼
現在我們有2個資料庫,一個是在另一個資料庫里,有引用另一個對象,以sysadmin運行一切正常。因此現在我們創建一個更實際的例子來打破代碼。代碼7.4在SourceDB資料庫里創建一個映射到SharedLogin的SourceUser,併在AlaskaCitiesView視圖上授予SELECT許可給用戶。然後代碼修改執行上下文到SharedLogin,嘗試訪問視圖。SELECT語句會成功麽?
1 USE SourceDB; 2 GO 3 4 -- Create a user in the SourceDB who will access the view 5 CREATE USER SourceUser FOR LOGIN SharedLogin; 6 GRANT SELECT ON dbo.AlaskaCitiesView TO SourceUser; 7 GO 8 9 -- Try accessing the view as SourceUser 10 EXECUTE AS LOGIN = 'SharedLogin'; 11 SELECT * FROM dbo.AlaskaCitiesView ORDER BY Population DESC; 12 GO 13 REVERT;
代碼7.4:創建SourceUser資料庫用戶,映射到SharedLogin,並用代碼測試訪問視圖
沒有成功,SELECT語句拋出了一個異常。
我們暫時先退一步。我們有完整的跨資料庫所有權鏈接:視圖和表享有共同成員資格,它是我的登錄(sysadmin),同時在資料庫里映射到dbo。到這裡都一切正常。但跨資料庫成員資格所有權鏈接沒有在資料庫實例里啟用,對2個新的資料庫也沒有啟用。接下來我們來啟用它。
啟用跨資料庫所有權鏈接
在SQL Server實例的全新安裝里,使用跨資料庫成員資格所有權鏈接的選項預設是關掉的。這是因為啟用這個選項,實例的安全護甲里打開了幾個小孔;在這篇文章里稍後會解釋。當這個選項禁用時,當代碼依賴於成員資格鏈接是,會生成許可拒絕的錯誤。(一會你就會看到,在讓代碼正常工作前,這不是你要修正的唯一問題,但是我們第一個要處理的)。
你可以在伺服器級別或資料庫級別啟用跨資料庫成員資格鏈接,在伺服器級別使用T-SQL語句或SSMS。
在伺服器級別啟用
對所有的資料庫,在伺服器級別啟用跨資料庫所有權鏈接選項。如果你啟用它,它是針對所有資料庫的,你不能在資料庫級別限制它。
使用SSMS,在對象瀏覽器右擊伺服器實例,從彈出的菜單選擇【屬性】。選擇【安全性】頁,在對話框的底部,你會看到【跨資料庫所有權鏈接】選項,如插圖7.1所示。點擊【確定】,在實例里的所有資料庫會啟用它。
插圖7.1:使用伺服器屬性對話框啟用跨資料庫所有權鏈接
你也可以使用T-SQL代碼做同樣的修改,如代碼7.5所示。和其它伺服器實例選項,設置cross db ownership chaining選項為1來啟用它,設回0禁止它。記得使用RECONFIGURE語句,這樣的話你不需要重啟實例讓修改生效。一旦你執行了這個代碼,你可以在這個資料庫實例里的任何資料庫里,使用跨資料庫所有權鏈接。
1 USE master; 2 GO 3 4 EXECUTE sp_configure 'cross db ownership chaining', 1; 5 RECONFIGURE;
代碼7.5:使用sp_configure系統存儲過程啟用跨資料庫所有權鏈接
不管你用SSMS還是T-SQL代碼來啟用跨資料庫所有權鏈接,現在把它關閉。這不是啟用它的最佳方式,除非你想在實例里的每個資料庫里從源對象里引用對象。不是的話,在實例級別啟用它太不安全,這樣做不明智。
只在需要的資料庫啟用跨資料庫所有權鏈接才是明智的。
在資料庫級別啟用
如果在伺服器級別你禁用了跨資料庫所有權鏈接,如果你想使用它的話,你必須在資料庫級別啟用它。如果對於一個資料庫禁用了,資料庫一點也不能參與跨資料庫所有權鏈接,不管是源還是鏈接資料庫。為了讓鏈接能夠工作,源和鏈接資料庫的設置必須啟用。
對於所有的資料庫,當你創建或附加它們的時候,預設跨資料庫所有權鏈接是禁用的。但對master,msdb,tempdb系統資料庫是啟用的,對於model資料庫是禁用的。因為SQL Server內部使用跨資料庫所有權鏈接,對於這些系統資料庫,你不能啟用或停用它。
提示:如果你分離,重新附加已經啟用跨資料庫所有權鏈接的資料庫,在附加回資料庫後,你需要重新啟用它。對於在伺服器級別啟用的無效,因為它自動應用到所有的資料庫。
可惜SSMS在資料庫屬性對象框里有跨資料庫所有權鏈接啟用選項,如果在插圖7.2選項頁所示,它是只讀的。為了修改資料庫的這個值,你需要使用代碼7.6,對SourceDB 和ChainedDB資料庫同時啟用。這個代碼使用ALTER DATABASE語句的SET DB_CHAINING選項來打開鏈接的開和關。
插圖7.2:對於ChainedDB資料庫,跨資料庫所有權鏈接選項是只讀的
1 ALTER DATABASE ChainedDB SET DB_CHAINING ON; 2 ALTER DATABASE SourceDB SET DB_CHAINING ON; 3 GO
代碼7.6:在兩個資料庫里,ALTER DATABASE代碼來啟用跨資料庫所有權鏈接。
在兩個資料庫里同時啟用了跨資料庫所有權鏈接,你可以再次嘗試用SharedLogin的安全上下文訪問視圖;代碼7.7再次展示這個代碼。
1 USE SourceDB; 2 GO 3 4 EXECUTE AS LOGIN = 'SharedLogin'; 5 SELECT * FROM dbo.AlaskaCitiesView ORDER BY Population DESC; 6 GO 7 REVERT;
代碼7.7:使用跨資料庫所有權鏈接訪問嫩跨資料庫邊界的對象
但代碼還是返回同樣的錯誤。這次的問題是還有另一個要求:訪問視圖對象的用戶必須要訪問鏈接資料庫。用戶在潛在的對象上不需要有許可。事實上,用戶在那個資料庫里不需要任何許可。
代碼7.8展示了你可以如何解決這個問題。代碼在ChainedDB資料庫創建了一個映射到SharedLogin的ChainedUser用戶。這給SharedLogin在那個資料庫里一個小立足點,這是跨資料庫所有權鏈接正常工作需要的。為了驗證SharedLogin在AlaskaCity表上沒有SELECT許可,代碼嘗試從AlaskaCity直接讀取數據。但那個嘗試失敗了,因為SharedLogin和ChainedUser在ChainedDB任何對象上沒有許可。
1 USE ChainedDB; 2 GO 3 CREATE USER ChainedUser FOR LOGIN SharedLogin; 4 -- Note that we're not granting the user any permissions in the chained database. 5 GO 6 -- Verify that SharedLogin doesn't have direct access to the AlaskaCity table, even in the ChainedDB database context. 7 EXECUTE AS LOGIN = 'SharedLogin'; 8 SELECT * FROM dbo.AlaskaCity; 9 GO 10 REVERT;
代碼7.8:創建映射到在ChainedDB里SharedLogin的用戶,但沒有任何許可,可以通過嘗試從AlaskaCity查詢數據
現在你可以執行代碼7.7,最後從視圖裡成功獲得數據。
你可以驗證跨資料庫所有權已經啟用,即使使用常見對象所有權,用戶在可以同時訪問兩個資料庫。你可以使用低嗎7.9關閉跨資料庫所有權鏈接——實際上你只要運行其中一個即可,因為只有2個資料庫都是啟用,跨資料庫所有權鏈接才可以正常工作——然後再次運行代碼7.7.這次你會得到剛纔一樣的錯誤。
1 ALTER DATABASE ChainedDB SET DB_CHAINING OFF; 2 ALTER DATABASE SourceDB SET DB_CHAINING OFF; 3 GO
代碼7.9:對2個資料庫關閉跨資料庫所有權鏈接
這是跨資料庫所有權鏈接要剋服的錯誤。
共同所有權
使用跨資料庫所有權鏈接啟用,代碼可以正常訪問視圖的原因是視圖和表有共同所有權——SharedLogin登錄。代碼假定你以sysadmin登錄到SSMS,因此在2個資料庫里所有創建的對象屬於dbo用戶,兩個都映射到sysadmin用戶。(跨資料庫所有權鏈接正常工作並不需要這個,這是讓代碼簡單和專註的一種方法)。你可以使用代碼7.10來驗證映射,它列出在資料庫里用戶資料庫和視圖的架構名稱,所有者用戶名和所有者登錄名。如果你在SourceDB和ChainedDB里運行代碼,你會發現OwnerLoginName是一樣的,如插圖7.3和插圖7.4所示,dbo用戶映射到sa登錄。
1 SELECT 2 so.[name] AS Object, 3 sc.[name] AS [Schema], 4 USER_NAME(COALESCE(so.principal_id, sc.principal_id)) AS OwnerUserName, 5 sp.name AS OwnerLoginName, 6 so.type_desc AS ObjectType 7 FROM sys.objects so 8 JOIN sys.schemas sc ON so.schema_id = sc.schema_id 9 JOIN sys.database_principals dp ON dp.principal_id = COALESCE(so.principal_id, sc.principal_id) 10 LEFT JOIN master.sys.server_principals sp ON dp.sid = sp.sid 11 WHERE so.[type] IN ('U', 'V');
代碼7.10:對於用戶資料庫和視圖,列出架構名,所有者用戶名和擁有者登錄名
插圖7.3:在SourceDB資料庫里運行代碼7.10的結果
插圖7.4:在ChainedDB資料庫里運行代碼7.10的結果
dbo用戶在一個資料庫里不是必須的,在另一個資料庫dbo用戶也不是必須的,理解這個非常重要。它們可以映射到完全不同的登錄或不映射。在鏈里,對於所有涉及到的對象,記錄的所有者有同個SID才是重要的。你可以使用代碼7.11來驗證對象擁有者的SID和登錄的SID是否一樣。(如果你想自己運行代碼的話,你會需要修改在最後部分的電腦名稱和用戶名)。
1 SELECT name, sid FROM SourceDB.sys.database_principals WHERE name = 'dbo' 2 UNION ALL 3 SELECT name, sid FROM ChainedDB.sys.database_principals WHERE name = 'dbo' 4 UNION ALL 5 SELECT 'PC201602202041\sa', SUSER_SID('PC201602202041\sa');
代碼7.11:驗證dbo用戶的SID是否和映射登錄的SID一樣
在的電腦上,代碼7.11的結果數據如插圖7.5所示。共同所有權!
插圖7.5:在SourceDB資料庫和ChainedDB資料庫里的dbo用戶SID,和在SSMS執行代碼的SID。
跨資料庫所有權鏈接風險
啟用跨資料庫所有權鏈接會有風險,因為有特殊地位用戶的許可權濫用。微軟描述了2個方式的風險,兩個都涉及了跨資料庫安全邊界的潛在風險。
- 在單個資料庫的上下文里,資料庫擁有者,db_ddladmin和db_owners資料庫角色的成員可以創建其它用戶擁有的對象。這些新對象可以在擁有同樣所有者的其它資料庫里使用對象,無意給了在其它資料庫的對象訪問。本質上來說,你應該在所有資料庫里信任這些特權用戶數據,取決於你在資料庫實例如何配置安全。
- 有CREATE DATABASE許可的資料庫用戶可以創建新的資料庫或附加資料庫到資料庫實例。跨資料庫所有權鏈接啟用後,這些用戶可以從這些新建或附加的資料庫訪問在其它資料庫里的對象。
如果你想啟用跨資料庫所有權鏈接的話,這裡的關鍵是你要信任你特權的用戶,這些許可已經超過了在特定表裡簡單訪問和數據維護。這也是微軟為什麼強烈推薦的一個原因,如果你需要啟用跨資料庫所有權鏈接,為了控制安全風險,你只為需要的資料庫啟用。
小結
跨資料庫所有權鏈接還是你保持你數據安全的另一個方法。這些選項禁用的話,對於惡意用戶很難訪問其它資料庫的數據。當在正確的場景和安全的環境里,你可以啟用這個選項讓對象所有者保持它們數據的完全控制。你應該幾乎從不子啊伺服器級別啟用跨資料庫所有權鏈接。應該是,在只有真正需要的資料庫上啟用它,並確定保護好特權用戶的濫用。
原文鏈接:
http://www.sqlservercentral.com/articles/Stairway+Series/123545/