WindowsNT安全性API簡介(轉)

PigBaby2007發表於2007-08-08

  安全性在作業系統中應該是相當容易實現的,對嗎?就是說,為任意物件指定某個安全級別所需要做的所有工作只是一個簡單的函式呼叫,例如GrantAccessTo或者DenyAccessTo,對嗎?

  [@more@]

  不幸的是,Windows NT安全性應用程式介面(API)看起來並不是那麼簡單。它包含了過多的與安全性有關的函式,並且僅僅為一個使用者開啟一個物件的工作就已經非常複雜了。

  

  要正確使用安全性API,需要按照下面幾個層次去理解:

  

  第一個層次是理解資料結構:訪問控制表(ACLs),訪問控制元素(ACEs),安全性描述符(SDs)和安全性IDs (SIDs)。

  第二個層次是理解ACLs的語義(雖然不需要理解它們是如何工作的)。根據ACLs建立順序的不同,對同一個使用者的訪問可能允許,也可能不允許。

  第三個層次是理解作業系統本身如何使用安全性。可以將安全性API理解成為伺服器應用程式提供用來保護物件不被未授權的使用者訪問的服務集合,同事務日誌幫助裝置驅動程式和應用程式記錄錯誤以及確認事件提供服務的方法相同。

  在這些服務只被第三方應用程式使用時,相當容易理解安全性是如何工作的。然而,Windows NT是一個安全的作業系統,此外,基於Windows NT的網路也非常依賴於安全性。因此,安全性結合到系統的方法就顯得很模糊。

  

  誰需要安全?

  在進入任何細節之前,先要明確為什麼會需要安全性。如果不是處於下面的情況,就根本不必為安全性擔心:

  

  正在寫一個伺服器應用程式,即幾個使用者都可以訪問的一個應用程式,而且此伺服器應用程式只限於為這些使用者的一個子集提供資料結構。

  

  注意這是一個相當廣泛的定義。下面是滿足條件的幾個例子程式。

  

  對於單機(沒有連網的計算機),編寫一個服務,Windows NT啟動以後一直執行,並且有多個使用者在此計算機上登入及退出。該服務提供的資訊只對少數使用者可見。例如,想收集使用模式或者登入資料,就可能只限於管理員訪問該資料。

  

  許多特許可權制在系統級。例如,系統登錄檔受保護,使得只有具有特殊特權的使用者能夠向系統中新增裝置驅動程式。這是由於安全性的原因。例如,一個惡意的使用者能夠利用裝置驅動程式監控使用者輸入的能力竊取其它使用者的工作。安全性也有助於系統的穩定。設想一個未經授權的使用者安裝了一個粗製濫造的裝置驅動程式。當其它使用者工作時,這樣的驅動程式會造成系統崩潰。透過將註冊新裝置驅動程式的權利限制給可信賴的使用者,能夠防止Windows NT的計算機上出現這種情況。

  

  許多在網路上工作得與單機上同樣好的伺服器程式得益於與安全性系統的某種掛鉤。例如,一個資料庫伺服器可能同時為幾個使用者服務,某些使用者不允許檢視給定資料庫中的某些資料。假設公司內的每個人都能夠查詢員工資料庫。管理人員需要訪問員工的全部資訊,而其他人則應該只能看到工作頭銜和辦公室編號。如果將包含工資和獎金資訊的欄位限制於管理人員訪問,就可以允許公司內所有的人使用同一個資料庫,而不會危及安全性和機密。

  

  安全性的微觀檢視

  安全性的一個問題是使用安全性API毫無新奇刺激可言。其他人編寫的程式碼可以旋轉茶壺、在視窗中顯示動畫、彈出很酷的Windows 95控制元件、透過MAPI來回傳送資料等等,而安全性程式設計卻總是令人厭煩的事情。

  

  Windows NT安全性表現的非常複雜,相比之下,從微觀水平上看則比較簡單。每個Windows NT域(或域組)儲存有一個該域所知道的使用者的資料庫。使用者想要在Windows NT的域中工作,必須先使用一個使用者名稱和口令證明自己。一旦安全性系統證明了口令,使用者就會被關聯到一個訪問令牌,識別使用者的內部資料結構。

  

  關於Windows NT下安全性必須知道的首要事情是它是以使用者為中心的;也就是說,試圖訪問受保護物件的每一行程式碼都必須與一個特殊使用者關聯,該使用者必須用口令向客戶機證明自己的身份。每次安全性檢查都要依靠使用者鑑別。例如,編寫程式碼阻止Microsoft Excel訪問一個物件是不可能的。可以保護一個物件防止Joe Blow執行Microsoft Excel訪問,但是如果允許Carla Vip訪問該物件,她可以使用Microsoft Excel或者其它喜歡的程式訪問,只要Carla使用只有自己知道的口令向客戶機證明自己的身份就行。

  

  安全性API雖然看起來很複雜,但是卻只完成兩件事:

  

  稽核:每次對特定的物件試圖有特定的操作時生成一個日誌條目。

  

  限制物件訪問:客戶程式呼叫的函式,可能會成功,失敗返回錯誤程式碼5(訪問被拒絕),或者因其它原因失敗,取決於伺服器如何指定特權。

  

  使用者可能不是直接看到錯誤資訊,而是一個對話方塊,上面寫著:“你沒有特權將雞蛋從紙盒中拿走。”彈出此對話方塊的程式內部可能包含下面的程式碼行:

  

  if (!RemoveEggsFromCarton() && GetLastError() == ACCESS_DENIED)

  

  AfxMessageBox("You do not have the privilege to remove the eggs from the carton");

  

  安全性機制

  Windows NT使用兩種導致訪問嘗試失敗返回錯誤5的機制:確認許可權和確認特權。許可權屬於物件上的行為,比如掛起執行緒許可權或讀檔案許可權。許可權總是與特定物件和已知使用者相關聯。例如,讀檔案許可權必須與檔案(許可權應用在此檔案上)和有或沒有許可權的使用者相關聯。同樣,掛起執行緒許可權除非與特定的執行緒和使用者關聯否則沒有用。

  

  特權是預先定義好的屬於系統上操作的許可權。例如,特權有除錯程式、備份和恢復儲存裝置以及裝入驅動程式。特權以使用者為中心,而不是物件。

  

  為了使兩者之間區分得更清楚,可以看一下實現許可權和特權的資料結構:許可權在叫作訪問控制表(ACL)的資料結構中指定。ACL通常與物件相關。使用者用訪問令牌表示。當使用者試圖訪問受保護的物件時,其訪問令牌與物件的ACL檢查。訪問令牌包含代表使用者的唯一識別符號(安全性ID,或SID)。ACL中的每個許可權與一個SID相關;這樣,安全性子系統就知道了與每個使用者相關的許可權。

  

  另一方面,特權在訪問令牌中編碼,所以沒有相關聯的物件。要確定使用者是否允許做某個與特權有關的操作,安全性子系統檢查訪問令牌。

  

  此外,許可權需要行為的說明(幹什麼的許可權?例如,讀檔案或者掛起執行緒),而特權不需要(使用者或者有特權,或者沒有)。與特權相隨的操作隱含在特權本身中。

  

  特權在訪問令牌中編碼的原因是大多數特權不考慮安全性需求。例如,允許備份儲存裝置的使用者必須能夠繞過檔案安全性。為了允許使用者訪問而給硬碟上每個單獨的檔案都加入一個新的ACE是不可行的。這樣,備份儲存裝置的程式碼首先檢查試圖備份的使用者是否擁有備份特權;如果有,單個檔案的安全性就被忽略。

  

  能夠與訪問令牌相關的特權集被牢固加密,不能被應用程式展開。伺服器程式能夠使用特殊的許可權和普通的對映實現自定的安全性規則。

  

  有兩種型別的ACL:自由決定的(DACL)和系統的(SACL)。DACL管制物件訪問,SACL管制稽核。

  

  控制訪問

  在大多數情況下,錯誤5是由Windows NT特有的叫作AccessCheck的Win32函式內部產生的。此函式的輸入有使用者的訪問令牌、需要的特權和ACL。ACL主要是小資料結構(叫作訪問控制元素,或ACE)的列表,每個資料結構定義一個使用者或一組使用者、一個許可權集合以及允許或拒絕的資訊。例如,ACL中可能有一個ACE寫著“從紙盒中拿走雞蛋的許可權明確地拒絕給與使用者Elephant和Bozo”,後面一個ACE寫著“從紙盒中拿走雞蛋的許可權明確地准予給與使用者Betty Crocker以及CHEFS組中所有使用者”。

  

  ACL與物件相關,可以在伺服器程式中動態建立。例如,如果一個檔案物件與一個ACL相關,不管何時有應用程式試圖開啟該檔案物件,ACL就會被查詢以決定是否允許執行應用程式的使用者開啟檔案。

  

  AccessCheck函式被許多系統函式內部呼叫,例如,CreateFile(使用者試圖在NTFS分割槽或命名管道上開啟檔案時)和OpenFileMapping。然而,Win32伺服器程式能夠直接呼叫AccessCheck,保護想保護的任何物件。

  

  注意安全性API函式只被伺服器程式呼叫;客戶不需要或直接使用安全性。客戶曾經看到的Windows NT安全性就是錯誤5。這使得Windows NT安全性可以不必考慮客戶執行的軟體。需要的是伺服器在域的安全性資料庫中確認客戶以及將從客戶收到的請求翻譯成伺服器端函式呼叫的能力。此函式或者隱含呼叫AccessCheck,或者根據伺服器端AccessCheck的輸出傳送或不傳送其結果。

  

  Windows NT security中容易混淆的部分是對AccessCheck的呼叫可能是非常模糊的。例如,Windows NT監控裝置驅動程式安裝的功能是一個非常模糊的概念。當試圖新增裝置驅動程式時使用者要訪問哪個“物件”?系統在哪裡呼叫AccessCheck以及必要時在哪裡將錯誤資訊顯示給使用者?

  

  在裝置驅動程式的例子中,答案還不是太困難:因為裝置驅動程式和系統透過登錄檔(Windows NT透過瀏覽登錄檔子樹,解釋每個條目,嘗試執行在單獨登錄檔項中指定的驅動程式二進位制檔案而裝入裝置驅動程式)互動,Windows NT保護的物件是登錄檔項,它在Windows NT中是可以得到的物件。在Win32 API層,任何操作登錄檔的嘗試將會翻譯成登錄檔工作的函式,例如RegOpenKey內部呼叫AccessCheck。

  

  除了登錄檔保護外,驅動程式二進位制檔案也有安全性問題。一個因訪問登錄檔被拒絕而落空的駭客仍然能夠用新增了額外功能的驅動程式副本取代原有的驅動程式執行檔案。這一過程不需要訪問登錄檔,所以Windows NT如何防止這類問題呢?相當簡單,透過要求驅動程式二進位制檔案存放在NTFS分割槽並限制對其訪問。這樣,取代驅動程式二進位制檔案的企圖(在Win32 API層上呼叫DeleteFile或CreateFile時不可避免地被終止)會被AccessChe

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10144097/viewspace-934683/,如需轉載,請註明出處,否則將追究法律責任。