SQL Server安全(6/11):執行上下文與代碼簽名(Execution Context and Code Signing)

来源:http://www.cnblogs.com/woodytu/archive/2016/03/28/5317096.html
-Advertisement-
Play Games

在保密你的伺服器和數據,防備當前複雜的攻擊,SQL Server有你需要的一切。但在你能有效使用這些安全功能前,你需要理解你面對的威脅和一些基本的安全概念。這篇文章提供了基礎,因此你可以對SQL Server里的安全功能充分利用,不用在面對特定威脅,不能保護你數據的功能上浪費時間。 SQL Serv ...


在保密你的伺服器和數據,防備當前複雜的攻擊,SQL Server有你需要的一切。但在你能有效使用這些安全功能前,你需要理解你面對的威脅和一些基本的安全概念。這篇文章提供了基礎,因此你可以對SQL Server里的安全功能充分利用,不用在面對特定威脅,不能保護你數據的功能上浪費時間。


SQL Server決定主體是否有需要的許可執行代碼的基本方式是它的執行上下文角色。這都是複雜的可能性,主體有執行代碼的許可,但沒有代碼訪問的潛在對象的許可,例如表裡的數據。這篇文章會探尋SQL Server執行上下文,所有權鏈接接,模擬,還有向你展示下如果通過T-SQL代碼控制數據訪問。

執行上下文

當用戶執行一個存儲過程或其它資料庫代碼時,SQL Server檢查確保,不僅用戶有運行存儲過程的許可,而且有代碼訪問使用資料庫對象的許可。沒有這類許可檢查,有些人會很容易創建可以讀取表,使用執行代碼訪問不需要其它的對象代碼。這會是重大的安全漏洞。

這個許可檢查過程不發生的唯一例外是代碼的所有者也是代碼訪問的所有潛在對象的所有者。在這個共同所有權下,SQL Server驗證調用者在代碼上有EXECUTE許可,不會繼續檢查許可。

例如,如果在存儲過程中的嗲嗎訪問三個表和四個視圖,SQL Server在執行代碼前進行這些概念上的步驟:

  1. 在代碼上驗證調用者有EXECTUTE許可。如果調用者沒有,返回一個錯誤並不再繼續。
  2. 檢查代碼的所有者是否也有代碼訪問對象的許可。如果共同所有權(common ownership)存在的話,停止檢查並執行代碼。
  3. 如果共同所有權(common ownership)不存在的話,檢查確保調用者代碼訪問的對象上有許可。如果調用者在一個或多個對象上沒有許可,返回一個錯誤且不執行代碼。
  4. 如果調用者有所有需要的許可,執行代碼。否則,返回錯誤且不執行代碼。

在代碼調用其它帶按摩或訪問其它對象的地方,共同所有權繼續檢查,即輪流調用其它代碼或訪問其它對象。只要鏈里的所有對象有同樣的所有者,許可檢查就不需要。但只要鏈里的一個對象比要訪問它的對象多出不同的所有者,在那個對象上的許可就檢查了。

在這鐘情形里的對象所有權被稱為所有權鏈接接(ownership chain),因為你不需要擔心代碼執行的安全上下文。這也是SQL Server的早期版本有擁有所有對象的特定dbo角色的直接原因。但任何時候你有共同所有權和許可來訪問一切,你就違法了最小特權許可,暴露你的數據在不需要的安全危機里。

幸運的是,在SQL Server里你可以修改代碼的安全執行上下文。

提示:

這篇文章會探尋執行在存儲過程上的執行上下文和代碼簽名,但它們同樣對大多數用戶自定義函數也支持。

修改執行上下文

一般你不想調用者的許可用來在破壞的所有權鏈接接里驗證許可。有時你想代碼好像完全被另一個用戶執行一樣,通過另一個用戶的許可在訪問的所有的對象上驗證許可。這稱為切換代碼的執行上下文。這讓你使用SQL Server顆粒度許可的優點,對潛在的對象保持完全的許可控制,但還是給不同用戶執行代碼的能力。

在SQL Server里,當你定義任何類型的用戶自定義函數(行內表值函數除外),存儲過程和觸發器,你可以使用EXECUTE AS子句作為對象定義的一部分,表示這個代碼應該在指定用戶的安全上下文下運行。

EXECUTE AS有4個可用選項:

  • EXECUTE AS CALLER:預設用戶向下相容。代碼在調用者的上下文里執行,調用者必須同時有執行代碼和訪問潛在對象的許可。實際的操作取決於所有權鏈接接上是否損壞或完好。
  • EXECUTE AS = ‘username’ and EXECUTE AS = ‘loginname’:代碼在指定用戶或登錄的上下文里運行,因此指定的用戶或登錄必須在所有的潛在對象上有許可。在這個情況下,調用者必須滿足下列之一:
    • 在代碼上有EXECUTE許可
    • 是sysadmin或db_owner,或者在伺服器或資料庫上有CONTROL SERVER許可,或者對於用戶有模仿(impersonate)許可。

使用用戶名的EXECUTE AS只能應用於伺服器範圍的DDL觸發器,且要登錄到觸發器。否則,提供的用戶名必須是有效的資料庫用戶名稱。

  • EXECUTE AS SELF:這是創建存儲過程的當前用戶的縮寫。和EXECUTE = [myUserName]等效。SQL Server目錄村裡寫代碼的實際用戶ID。
  • EXECUTE AS OWNER:這是在指定用戶的安全上下文運行的另一個變體,在這個情況下,代碼所有者在代碼執行時間,而不是在創建時間。如果在資料庫里,擁有者在代碼創建後修改了,這表示代碼會在和首次創建代碼的不同用戶的許可執行。

當你在SSMS里運行代碼時,在會話的執行上下文里,有兩種EXECUTE AS的變體可以作為語句使用。它們是EXECUTE AS LOGIN = ‘loginname’ 和EXECUTE AS USER = ‘username’。當用戶登錄到SQL Server實例時,會話開始,那個時候的執行上下文設置為登錄的用戶,用作許可檢查。EXECUTE AS 修改會話期間執行上下文,直到用戶執行了REVERT語句。

通過EXECUTE AS修改安全上下文的任何時間,代碼創建者或會話用戶在語句里指定的用戶必須有模仿(impersonate)許可。你永遠不需要模擬自己的許可,例如EXECUTE AS SELF。

使用EXECUTE AS子句

在資料庫里,假設你有Vendor表。表在SchemaUserTable架構里定義,屬於UserTable用戶。代碼6.1定義了範文這個表的存儲過程。在SchemaUserProc定義的存儲過程,屬於UserProc用戶。因為表和存儲過程在屬於不同用戶的不同架構里定義,存在斷開的所有權鏈接接。

1 USE ExecuteContextDB;
2 GO
3 CREATE PROC SchemaUserProc.VendorAccessProc @state CHAR(2)
4 AS 
5     SELECT * FROM SchemaUserTable.Vendor WHERE state = @state;
6 GO

代碼6.1:創建在一個在一個架構里訪問不同架構里的表的存儲過程,這裡架構有不同的擁有者。

提示:

下麵的代碼會創建登錄、資料庫、用戶和這個部分使用的架構,同樣也會在Vendor表裡插入一些記錄。先運行下列帶代碼再運行代碼6.1。

 1 -- Create the logins and database for this demo
 2 USE master;
 3 GO
 4 
 5 IF SUSER_SID('UserProc') IS NOT NULL DROP LOGIN UserProc;
 6 IF SUSER_SID('UserTable') IS NOT NULL DROP LOGIN UserTable;
 7 IF SUSER_SID('RealUser') IS NOT NULL DROP LOGIN RealUser;
 8 GO
 9 CREATE LOGIN UserProc WITH password = 'Y&2!@37z#F!l1zB';
10 CREATE LOGIN UserTable WITH password = 'Y&2!@37z#F!l1zB';
11 CREATE LOGIN RealUser WITH password = 'Y&2!@37z#F!l1zB';
12 GO
13 
14 IF DB_ID('ExecuteContextDB') IS NOT NULL DROP DATABASE ExecuteContextDB;
15 CREATE DATABASE ExecuteContextDB;
16 GO
17 USE ExecuteContextDB;
18 GO
19 
20 -- Create the users 
21 CREATE USER UserProc;
22 CREATE USER UserTable;
23 CREATE USER RealUser;
24 GO
25 
26 -- Create the schemas 
27 CREATE SCHEMA SchemaUserProc AUTHORIZATION UserProc;
28 GO
29 CREATE SCHEMA SchemaUserTable AUTHORIZATION UserTable;
30 GO
31 
32 -- Create a table and a proc in different schemas to ensure that 
33 -- there is no ownerhship chaining.
34 CREATE TABLE SchemaUserTable.Vendor 
35     (ID INT, name VARCHAR(50), state CHAR(2), phno CHAR(12));
36 GO
37 SET NOCOUNT ON
38 GO
39 INSERT INTO SchemaUserTable.Vendor VALUES (1,'Vendor1','AK','123-345-1232');
40 INSERT INTO SchemaUserTable.Vendor VALUES (2,'Vendor2','WA','454-765-3233');
41 INSERT INTO SchemaUserTable.Vendor VALUES (3,'Vendor3','OR','345-776-3433');
42 INSERT INTO SchemaUserTable.Vendor VALUES (4,'Vendor4','AK','232-454-5654');
43 INSERT INTO SchemaUserTable.Vendor VALUES (5,'Vendor5','OR','454-545-5654');
44 INSERT INTO SchemaUserTable.Vendor VALUES (6,'Vendor6','HI','232-655-1232');
45 INSERT INTO SchemaUserTable.Vendor VALUES (7,'Vendor7','HI','453-454-1232');
46 INSERT INTO SchemaUserTable.Vendor VALUES (8,'Vendor8','WA','555-654-1232');
47 INSERT INTO SchemaUserTable.Vendor VALUES (9,'Vendor9','AK','555-345-1232');
48 GO

代碼6.2在存儲過程上授予EXECUTE許可給真正的用戶,RealUser,它會運行代碼。

1 -- Grant permissions on the stored procedure
2 GRANT EXECUTE ON SchemaUserProc.VendorAccessProc TO RealUser;
3 GO

代碼6.2:在新的存儲過程上授予EXECUTE許可。

在SSMS里,你可以運行EXECUTE AS作為臨時修改安全上下文的在查詢窗體里運行的代碼語句。使用代碼6.3修改安全上下文為RealUser來運行存儲過程獲得在位於阿拉斯加的供應商列表。

1 EXECUTE AS user = 'RealUser';
2 EXEC SchemaUserProc.VendorAccessProc 'AK';

代碼6.3:修改執行上下文,以RealUser運行存儲過程。

執行這個代碼引起了下列錯誤:

在對象Vendor上,SELECT許可被拒絕,資料庫 'ExecuteContextDB',架構 'SchemaUserTable'。

問題是所有權鏈接接斷開了——存儲過程的所有者和表的所有者不同——RealUser在Vendor表上沒有SELECT許可。這裡有SQL Server如何從概念上分析情況:

  • 調用者是RealUser,它有EXECUTE許可。通過!
  • 存儲過程的所有者是UserProc。表的所有者是UserTable。這表示有斷開的所有權鏈接接,因此檢查調用者RealUser,在代碼里有進行操作的許可。
  • RealUser在Vendor表上沒有SELECT許可,拋出錯誤。失敗!

你可以在存儲過程定義里使用EXECUTE AS子句來修正問題,假設你是存儲過程的創建者,在這個情況里想允許RealUser運行代碼。首先,使用代碼6.1顯示的REVERT語句來撤銷安全上下文的RealUser切換,返回你自己的安全上下文:

1 REVERT;

代碼6.4:恢復用戶運行SSMS的原始安全上下文

接下來,修改存儲過程來包含EXECUTE AS子句使用UserTable的安全上下文來運行存儲過程,它在表上擁有SELECT許可,如代碼6.5所示。

1 ALTER PROC SchemaUserProc.VendorAccessProc @state CHAR(2)
2 WITH EXECUTE AS 'UserTable'
3 AS 
4     SELECT * FROM SchemaUserTable.Vendor WHERE state = @state;
5 GO

代碼6.5:修改存儲過程,在運行時間使用EXECUTE AS修改運行上下文

提示:

在這個例子里,UserTable通過成員資格擁有在Vendor表上的SELECT許可。但成員資格沒有必要用來執行上下文切換工作。例如,可以通過表擁有者授予用戶EXECUTE AS user許可。

然後修改安全上下文為UserTable,再次嘗試運行存儲過程,使用代碼6.6。

1 EXECUTE AS user = 'RealUser';
2 EXEC SchemaUserProc.VendorAccessProc 'AK';
3 REVERT;

代碼6.6:測試修改後的存儲過程來看看RealUser現在能否執行代碼。

這次調用成功,因為當SQL Server在所有權鏈接接檢查許可時——還是斷開的——它發現UserTable有需要的SELECT許可。結果如插圖6.1所示。

插圖6.1:在不同的用戶安全上下文下運行存儲過程的結果

代碼簽名

使用EXECUTE AS子句修改T-SQL代碼段的安全上下文只是解決斷開所有權鏈接接問題的一種方法。另一個方法是使用證書或非對稱匙的簽名代碼。這個技術授予代碼本身許可,不需要你修改運行上下文或取決於調用者的許可。而且通過證書的使用或非對稱匙的嚴格控制,你還是可以控制哪個主體能利用運行代碼的許可。

這個方式的方法是你創建一個安全,加密的證書或非對稱匙,然後創建與證書或匙關聯的用戶。這是特別的用戶類型,不關聯登錄。你分配需要的許可來運行到用戶的存儲過程,然後使用ADD SIGNATURE語句分配證書或匙到存儲過程。存儲過程使用證書或匙關聯的用戶許可。

即使存儲過程使用EXECUTE AS語句修改執行上下文,你還是可以使用這個技術。代碼簽名的常見情形是,修改執行上下文到代碼需要執行的最多許可的運行上下文,然後使用代碼簽名添加一個或多個額外許可。

和往常一樣,需要通過實例來演示下這個技術。代碼6.7創建再次從ExecuteContextDB資料庫的Vendor表獲取數據。UnsignedProc存儲過程沒有簽名,因此當RealUser運行它的時候會失敗。SignedProc存儲過程會簽名,對於RealUser用戶會正常運行。

 1 CREATE PROC SchemaUserProc.UnsignedProc @state CHAR(2)
 2 AS
 3     SELECT * FROM SchemaUserTable.Vendor WHERE state = @state;
 4 GO
 5 CREATE PROC SchemaUserProc.SignedProc @state CHAR(2)
 6 AS
 7     SELECT * FROM SchemaUserTable.Vendor WHERE state = @state;
 8 GO
 9 
10 GRANT EXECUTE ON SchemaUserProc.UnsignedProc TO RealUser;
11 GRANT EXECUTE ON SchemaUserProc.SignedProc TO RealUser;
12 GO

代碼6.7:創建唯一的存儲過程並對RealUser在它們上面授予EXECUTE許可

但這次,我們不是通過修改運行上下文授予SELECT許可,我們會創建一個證書,如代碼6.8所示。代碼然後創建從證書創建一個用戶,對用戶在Vendor表上授予SELECT許可。最後,代碼使用ADD SIGNATURE語句添加證書到SignedProc存儲過程。註意只有SignedProc拿到簽名;UnsignedProc還是沒簽名。

 1 CREATE CERTIFICATE MyCertificate
 2     ENCRYPTION BY PASSWORD = 'SZ6T4O^ff&1Kr3s?m\*'
 3     WITH SUBJECT = 'Certificate to sign SignedProc';
 4 GO
 5 
 6 CREATE USER MyCertificateUser 
 7     FROM CERTIFICATE MyCertificate;
 8 
 9 GRANT SELECT ON SchemaUserTable.Vendor TO MyCertificateUser;
10 GO
11 
12 ADD SIGNATURE TO SchemaUserProc.SignedProc BY CERTIFICATE MyCertificate
13     WITH PASSWORD = 'SZ6T4O^ff&1Kr3s?m\*';
14 GO

代碼6.8:實現證書和分配許可到代碼的代碼

最後,到測試簽名架構代碼的時候了,如代碼6.9所示。結果如插圖6.2所示,UnsignedProc有斷開的所有權鏈接接,RealUser在Vendor表上沒有SELECT許可,因此執行失敗。SignedProc通過使用代碼簽名授予SELECT許可,成功執行返回三條阿拉斯加的數據。

1 EXECUTE AS USER = 'RealUser';
2 
3 -- Can't run UnsignedProc
4 EXEC SchemaUserProc.UnsignedProc 'AK';
5 -- Can run SignedProc
6 EXEC SchemaUserProc.SignedProc 'AK';
7 
8 REVERT;

代碼6.9:測試使用證書簽名的代碼

插圖6.2:測試在UnsignedProc和SignedProc存儲過程代碼簽名的結果

配置這個有點複雜,但安全上受益非常值得。使用正確的話,這個技術剔除了用戶在潛在對象上需要的SELECT許可和存儲過程上的EXECUTE許可。很可能這不是你在存儲過程或用戶自定義函數里廣泛使用的,但當處理斷開的所有權鏈接接且沒有方便的擁有需要許可的主體時,它漂亮的解決了一些安全問題。

小結

在SQL Server里創建存儲過程和用戶自定義函數的最簡單方法是用完整的所有權鏈接接來是實現它們,代碼的所有者也擁有代碼訪問的所有資料庫對象。但通常這並不可行,當在SQL Server實例里對象的成員資格在多個主體間分發的時候。這篇文件介紹了你可以處理斷開的所有權鏈接接的兩個技術,通過修改執行上下文和使用代碼簽名分配許可。這些技術是免費贈送的,因此你可以對單個存儲過程或函數一起使用它們。那樣的話,你可以處理你面對的任何許可架構,來保持你的資料庫及它的資料庫儘可能的安全。

原文鏈接

http://www.sqlservercentral.com/articles/Stairway+Series/121476/


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • MySQL有三個版本:二進位,源碼包,RPM。 下麵講講二進位包的安裝過程 下載地址: http://dev.mysql.com/downloads/mysql/ 選擇Linux-Generic 我這裡選擇的是mysql-5.6.28-linux-glibc2.5-x86_64.tar.gz 解壓後 ...
  • 有時候需求需要隨機從資料庫查詢若幹條記錄集,網上搜了一下,幾篇博文都是些重覆的.....不知道他們誰抄的誰的,這裡除了介紹提供一種筆者自己想到的方法,本質都是利用mysql 的rand() 第一種方法: SELECT * FROM reportcard_patient_temp ORDER BY R ...
  • 中科院Oracle 10G 資料庫系統培訓視頻教程(828MB )第一章、安裝及體繫結構概述 Oracle資料庫基礎知識第二章、SQL*PLUS 基礎、實例的創建啟動與關閉第三章、SQL語言基礎第四章、PL/SQL基礎第五章、PL/SQL高級應用第六章、視圖、同義詞、序列第七章、觸發器第八章、安全管 ...
  • 1.做訂閱發佈的2台Sql伺服器最好要版本一致,不能出現類似如下情況: Sql2008 R2[發佈] - Sql2008[訂閱]; Sql2008 R2[發佈] - Sql2012[訂閱] 2.訂閱發佈理論上必須 訂閱發佈資料庫 都要在 同一個 區域網,但也可以穿透區域網 嘗試實現以下, 資料: h ...
  • 主要講下redis的安裝配置,以及以服務的方式啟動redis 1.下載最新版本的redis-3.0.7 到http://redis.io/download中下載最新版的redis-3.0.7 下載後,將redis-3.0.7.tar.gz複製到虛擬機中目錄/home/lewis/dev_soft中 ...
  • sql_查詢select /****** Script for SelectTopNRows command from SSMS ******/ SELECT TOP 1000 [r_gonghao] ,[r_mingzi] ,[r_bumen] ,[r_xingbie] FROM [moge].[... ...
  • 一、基礎 源碼地址:http://www.jinhusns.com/Products/Download/?type=xcj 1.應用 1)、應用 tn_Applications 欄位名稱 欄位類型 可空 特殊 預設值 欄位描述 ApplicationId int no 主鍵 應用程式Id Appli ...
  • 創建一個表記員工個人信息: SQL> Table created 1 row inserted 1 row inserted 1 row inserted 1 row inserted 1 row inserted 1 row inserted 1 row inserted 1 row insert ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...