Win32程序設計之系統安全

說明:第一次看到能把NT安全相關部分描述得比較完整和清晰的,不得不收藏!

 

Windows NT最迷人的部分之一是它的安全系統。如果你對安全方面不太關心,你可以完全忽略這部分的 Win32 API。然而, 在不少情況下,NT內置的安全特性可以幫助解決一些很有趣的問題。在這篇文章中,你將會理解到NT安全系統的意圖,這些概念將會幫助你懂得它的用處,以及操作它的技術。

  要注意的是,本文後的一些代碼,要用管理員的身份登錄才能夠運行。只有管理員才擁有執行這裏討論的某些系統安全任務的權限。

  NT安全性可以做到的事情

  在大多數的人看來,NT是一個頗爲完整和複雜的安全系統。經驗豐富的UNIX程序員對UNIX操作系統的文件安全系統很熟悉,並且瞭解root權限的含義。不過這些系統與NT的相比都是較爲簡單的。接下來的例子將讓你對NT的安全系統有所瞭解。

  由文件管理器的安全菜單和安全編輯器中,我們可以看到NT中內置的安全特性。你可以寫自己的代碼來修改NT文件系統捲上的安全信息,而且可以做到與它一樣詳細。在你寫的程序中, 你可以控制誰有某種類型的權限來訪問NTFS捲上的文件, 就象文件管理器的工作一樣。 

  .你可以在系統上創建一個命名管道,該管道只有其它系統上的管理員能夠訪問。當用戶嘗試着與服務器進行連接時,安全系統將進行檢查,以確保只有擁有相應訪問權限的用戶才能訪問,而拒絕沒有管理員權限的用戶。你可通過這種方法來讓不同機器上的管理員能相互溝通,同時又確保安全性。你可以寫代碼來選擇允許訪問或者拒絕訪問的用戶或用戶組。

  .你可以創建一個帶安全標記的mutex,只允許某些用戶或組來訪問它。這個處理可以應用在系統中的任何對象上:包括有文件、semaphores、線程、事件、文件映射中的共享內存等。對於mutex,你可以使用這個處理來防止對一個應用的同步機制的非法訪問;

  .你可以在某個對象(例如一個線程、mutex、管道、文件或註冊鍵)被訪問時,在事件日誌中創建一個項目。你能指定訪問的類型和用戶,並且產生一個事件日誌項目。例如, 對於某個文件,你可以設置爲在用戶smith成功讀取該文件時,產生一個事件日誌項目。

  由上面的例子中,我們可以知道NT可讓你對系統中的對象設置精確的安全訪問權限,並且允許你監視和記錄對象是怎麼使用的。

  NT安全系統的術語和概念

  NT安全系統有大量的新概念以及描述這些概念的詞彙,這裏將把這些概念用簡單的詞語表述,以便於你理解。

  你對安全系統中最常見的部分應該很熟悉了:這就是密碼。你可以將密碼系統看成是一棟建築物前門的鎖。密碼系統的作用就象一把鎖把建築物內外的事物隔離開來。你的密碼就相當於開門的鑰匙,讓你進入NT系統。

  如果你的硬盤是用NT的文件系統格式化的話,你知道NT的安全系統還有第二層。你可以將這一層看成是建築物裏面的各個房間的鎖。某些房間是打開的,任何人都可以進去,但一些是上了鎖的。每個房間的鎖都是有點不同的。例如,在使用NT文件格式化的卷中,如果你在上面創建了一個文件,你就可以爲它設置多種不同的訪問權限:

  .只有文件的擁有者才能訪問它

  .只有某個用戶才能訪問它

  .某些用戶可以訪問它

  .你可以設定爲某個組的成員才能訪問它

  .你可以設定爲某個組的成員才能訪問它,同時又拒絕該組中的某些用戶對它的訪問

  .可以設置爲多個組的成員均可訪問它

  .任何人都可以訪問

  可將每個受保護的文件看成是一個房間。你對文件的安全設置就象是房間的一把鎖,用來決定誰允許進入房間。你還可以控制當一個人進入房間時,可允許他做的事情。例如,對於一個文件,你可以給一個用戶讀的權限,給另一個用戶寫的權限等。打開文件管理器的安全菜單,看一下其中的權限對話框,你可以嘗試做不同的設置。

  NT就象一個有着很多房間的建築物。你的密碼就相當於一把鑰匙,讓你進入到建築物中。一旦就入了建築物,你就可以使用自己的鑰匙來進入不同的房間。一些房間是沒有上鎖的,有一些是上鎖的,但你可以進去,另外有一些是拒絕你進入的。房間就相當與NT系統中的各個對象:文件,註冊子鍵,線程和mutex對象等。

  你還可以在房間的門口加入一個崗哨,崗哨的任務是監視誰使用房間,並且他是怎樣使用的。這在NT中稱爲審覈。當你在一個NT對象上加入一個審覈時,當某些用戶以某種方式來訪問該對象時,該對象就會在事件日誌中寫入相關的項目。例如,如果你可以訪問一個NT文件系統卷,並且有管理的權限,打開文件管理器並且選擇一個你擁有的文件,然後在安全菜單中選擇審覈的選項。對於每個獨立的用戶或者組,你都可以設置什麼時候進行審覈,可以是在他們成功(或者失敗,或者兩者均是)打開文件、寫入文件、執行文件等時候。

  要了解這些安全特性,最方便的是在NT的文件系統中。通過文件管理器中的安全編輯器,你能夠以圖形化和簡便的形式爲文件設置各種不同的安全特性。這些安全細節的劃分對於NT中的許多對象都是適用的。例如,你可以用同樣的方式保護註冊表中的項目,實際上,註冊表編輯器包含有與文件管理器相似的可視化安全編輯器。你還可以爲許多內部的系統對象設置安全屬性。例如,你可以用這種方式來限制對一個命名管道的訪問。

 

 

以下就是上面所討論的概念的簡要總結

  .一個NT系統就象一棟建築物。你的密碼就相當於一把鑰匙,可讓你進入建築物。

  .進入建築物後,你就會發現有成千上萬個房間。一個文件就相當於一個房間,註冊表項目、命名管道和線程等也類似。

  .每個房間的安全是由擁有者來設置的,可設置爲只讓某個人使用、一羣用戶使用、某個組或者任何人訪問;

  .每個房間還可以加入一個崗哨,負責檢查和記錄誰進入房間以及每個人進入後做了些什麼;

  現在你已經有了一些基本的概念,以下再談一下NT在安全方面的一些特別的術語。

  NT的安全術語

  當你登錄入一個NT系統時,系統將給你一個訪問的記號。這個訪問記號是你用來打開NT系統中的鎖的鑰匙。你的鑰匙可以打開一些鎖,但是有一些它打不開。你所做的每個處理都包括有一個你的訪問標記的副本。

  這個訪問的標記用來做兩件不同的事情。首先,它用來標識你的身份。例如,當你以用戶“smith”的身份登錄時,你的訪問記號就包含了該用戶的標識。訪問記號還用來標識你屬於的所有組。例如,在用戶管理器中,你可能是Power User組,Backup Operator組和一個名爲Programmers的自定義組的成員。你的訪問記號就可以標識你爲這些不同組的成員。

  你的訪問記號還包含該用戶的所有權限。你所屬的每個組都擁有一些相關的用戶權限。如果你打開用戶管理器,你將可以在用戶權限菜單中看到權限的列表。例如,power users用戶組擁有設置系統時間的權限,而普通的用戶沒有。某些用戶可以關閉系統,某些不行。系統通過將你所屬每個組的所有權限組合起來,得到你的權限列表,並且放在你的訪問記號中。管理員還可以通過用戶管理器,爲每個用戶分配一些特別的權限。



***************圖一*****************

  一個訪問記號包括有一個用戶ID,用戶所屬的組名和由所有這些組得到的用戶權限列表。

  系統中的大部分對象都可以有自己的鎖。在NT中,一把鎖被稱爲一個安全描述器。如果在某個對象的創建函數包含有一個安全的參數,你就可以加入一把鎖。以下的對象都可以有鎖:

  .文件(如果它們存放在一個NT文件系統卷中)

  .目錄(如果它們存放在一個NT文件系統卷中)

  .註冊鍵

  .進程

  .線程

  .Mutexes

  .Semaphores

  .事件

  .命名管道(在系統或者網絡上)

  .匿名管道(僅在系統中)

  .Mailslots(僅在系統中)

  .控制檯屏幕緩衝

  .文件映射

  .服務

  .私有的對象

  要鎖上一個對象,你要創建一個安全描述器,並且在創建對象的時候將它傳送給該對象。如果將安全屬性參數的值設置爲0,則表示系統爲該對象創建一個默認的安全描述器,從而允許你訪問該對象。

  一個安全描述器包含有四個方面:

  .一個擁有者標識符,用來標識該對象目前的擁有者是誰

  .一個主要的組標識符


  .一個系統訪問控制列表(SACL,system access control list),包含有審覈的信息

  .一個自由訪問控制列表(DACL,discretionary access control list),用來決定那些用戶和組和可以訪問,那些不可以

  NT對象的擁有者可以隨時更改對象的安全信息。例如,如果你擁有一個文件,並且將它設置爲沒有人可以訪問它,以後,你還可以改變它的安全信息,因爲你是它的擁有者。這就象打壞鎖進入你的房間一樣,雖然鎖被打壞了,但是你可以換一把新鎖,因爲你是房間的擁有者。



*************圖二******************

  任何對象的安全描述器包含有用戶和組的ID、控制訪問權限的自由訪問控制列表,以及控制審覈信息的系統訪問控制列表。

  DACL是這把鎖的核心。它用來控制誰可以訪問、禁止誰訪問該對象。它是一個訪問控制列表,或者簡稱爲ACL,其中包含有訪問控制項目(ACE)。每項ACE都說明了一個用戶或者組,以及它們的權限。例如,如果對象是一個文件,用戶“smith”可允許讀取該文件,這樣就會有一個ACE指示用戶“smith”擁有讀取的權限。這也稱爲一個訪問允許ACE,因爲它允許一個用戶或者組做某件事情。同樣,還有一個訪問拒絕ACE,用來禁止某個用戶或者組訪問。例如,你允許Power Users組訪問一個對象,但對於“smith”用戶,他雖然屬於power user,但你不想他可訪問到該對象,使用一個拒絕訪問ACE就可以了。

  SACL(System Access Control List,系統訪問控制列表)也包含有ACE,不過這些ACE是用來決定誰將被審覈以及審覈的原因。SACL中的一個ACE被稱爲一個審覈訪問ACE。例如,當“smith”用戶成功打開一個文件時,是否要創建一個審覈項目呢?這個是由SACL中的一個ACE項目指定的。



**************圖三****************

  一個訪問控制項目(ACE)指定一個用戶(或者組)和所允許的訪問類似。ACE都存儲在ACL中。

  一個ACL中的每個ACD都由三部分來組成:一個安全標識符(SID,Security Identifier),一個訪問掩模和一個ACE頭。SID是存儲在註冊表中的一個值(也可通過函數調用得到),可唯一標識用戶管理器中的每個用戶或者組。ACE頭用來決定ACE的類型:訪問控制,訪問拒絕等。一個掩模有32位,用來決定用戶可對對象進行的操作。有一些標準的權限應用於系統中所有的對象,還有一些對象有特別的訪問權限,可在這些對象上應用。例如,以下就是一個文件對象可應用的特別和標準訪問權限:


specific:
FILE_READ_DATA 
FILE_WRITE_DATA 
FILE_APPEND_DATA 
FILE_READ_EA 
FILE_WRITE_EA 
FILE_EXECUTE 
FILE_READ_ATTRIBUTES 
FILE_WRITE_ATTRIBUTES 
FILE_ALL_ACCESS 

standard:
DELETE 
READ_CONTROL 
STANDARD_RIGHTS_ALL 
STANDARD_RIGHTS_EXECUTE 
STANDARD_RIGHTS_READ 
STANDARD_RIGHTS_REQUIRED 
STANDARD_RIGHTS_WRITE 
SYNCHRONIZE 
WRITE_DAC 
WRITE_OWNER 

generic:
GENERIC_ALL 
GENERIC_EXECUTE 
GENERIC_READ 
GENERIC_WRITE 



  generic權限是預定義的標準(standard)和特定(specific)權限的混合,對於各種對象都是不同的。

  訪問掩模是一個32位的位掩碼。在掩碼中,每個standard、specific和generic權限都有一個位與之相關。開頭的16位保存的是specific的權限,並且也是該訪問掩碼所指對象的鍵(例如,上面的FILE_ constants )。接着的8位保存的是standard權限。高4位保存generic權限。



*************圖四****************

  NT的安全特性使用了不少的新術語,不過,通過例子中的代碼,你將會逐漸熟悉所有這些名詞,並且也更容易理解所有這些概念。以下就是一個簡要的總結:

  .用戶登錄後,他們將得到一個訪問記號。一個訪問記號包含有用戶的ID,用戶組和用戶所屬組得到的用戶權限

  .每個對象都擁有一個安全描述器,就象它的鎖一樣。一個安全描述器包含有一個用戶和組標識符,一個系統ACL和一個Discretionary ACL。

  .一個DACL控制誰允許訪問及可以對對象做什麼操作

  .一個SACL控制要審覈誰對一個對象的某種處理

  .ACL由ACE組成。每個ACE包含有一個SID,用來標識用戶或者組,一個訪問掩模,用來決定允許用戶或者組做何種處理,還有一個ACE頭,決定ACD的類型。

  以下的部分提供了兩個簡單的例子,將所有這些術語組合在一起,並且展示了這些安全設置是如何運作的。

 

簡單的例子

  這部分的重點是談一個文件對象的安全描述器的創建和應用。這裏選擇了文件對象作例子的原因是由於它是常見的而且易於理解,你也可以通過文件管理器中的安全編輯器很容易地查看代碼的運行結果。不過,如果你的硬盤並不是使用NT的文件系統來格式化的話,這些代碼將是沒有用處的,而且安全編輯器也是不可用的。你可以採用以下三種方式來處理:

  1。重新使用NTFS來格式化硬盤,並且重新安裝NT,或者使用convert命令來將你的硬盤轉換爲NT的文件系統;

  2。裝入一個新的硬盤,並且使用NT的文件系統來格式化

  3。在你的硬盤中分出一小部分(大概10M),並且使用NTFS來格式化,這意味着你將必須重新格式化和重裝原有的分區

  或者,你可以先等一下,我們還會將同樣的代碼應用到一個註冊鍵中。無論你使用的是哪種文件系統,你將可以在註冊表編輯器中看到安全編輯器。

  以下的代碼包含了一個創建新文件的程序。爲新文件創建的安全描述器設置爲只有“guest”的用戶纔可以使用這個文件,而且該用戶只有讀的權限。這個程序沒有任何的錯誤檢測,因此你很容易看出其中的要點。當你運行代碼的時候,它將會在c:/創建一個testfile的文件。在文件管理器中選擇該文件,然後選擇安全菜單中權限選項。你將會看到列表中只有一個項目:只有“guest”可以讀取該文件。在你運行這些代碼時,你可以任意改變文件名或者用戶的名字。


#include 
#include 

SECURITY_ATTRIBUTES sa;
SECURITY_DESCRIPTOR sd;
BYTE aclBuffer[1024];
PACL pacl=(PACL)&aclBuffer;
BYTE sidBuffer[100];
PSID psid=(PSID) &sidBuffer;
DWORD sidBufferSize = 100;
char domainBuffer[80];
DWORD domainBufferSize = 80;
SID_NAME_USE snu;
HANDLE file;

void main(void)
{
InitializeSecurityDescriptor(&sd,
SECURITY_DESCRIPTOR_REVISION);
InitializeAcl(pacl, 1024, ACL_REVISION);
LookupAccountName(0, "guest", psid,
&sidBufferSize, domainBuffer,
&domainBufferSize, &snu);
AddAccessAllowedAce(pacl, ACL_REVISION,
GENERIC_READ, psid);
SetSecurityDescriptorDacl(&sd, TRUE, pacl,
FALSE);

sa.nLength= sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = FALSE;
sa.lpSecurityDescriptor = &sd;

file = CreateFile("c://testfile", 
GENERIC_READ | GENERIC_WRITE, 
0, &sa, CREATE_NEW, 
FILE_ATTRIBUTE_NORMAL, 0);
CloseHandle(file);
}



  首先看看程序的末尾,你將會發現一個對CreateFile的調用,該調用創建了一個名字爲c:/testfile的文件。不過,這個調用擁有一個安全的參數,它位於參數列表的第4位。你可能在不少的NT代碼中看到這個參數通常爲0。0值讓操作系統在創建對象的時候,使用一個默認的安全描述器。0值還會禁止繼承。上面的代碼使用一個SECURITY_ATTRIBUTES來代替,其中包含有一個有效的安全描述器。

  安全描述器首先在第一行通過調用InitializeSecurityDescriptor函數創建。(對於本文用到的函數,可見SDK中的Win32幫助文件或者Visual C++的幫助文件得到更多的信息)。這步使用絕對(absolute)的格式創建一個安全描述器(還有第二種稱爲自相關的格式)。新的安全描述器在初始化時除了修改級別的信息外,沒有其它的信息:沒有擁有者的標識符,沒有組的定義,沒有SACL,也沒有DACL。

  下一行調用InitializeAcl來創建ACL,它將成爲該安全描述器的DACL。當InitializeAcl函數返回時,pacl指向一個空的ACL。這就是說,ADL中沒有ACE。如果你註釋掉下面的兩行,這個空的ACL就會被放到安全描述器中,並且這個安全描述器會應用到文件,這時就沒有人可以訪問到這個文件。這是因爲discretionary ACL中沒有任何的ACE。如果你不創建DACL,並且在DACL安全步驟中傳入一個NULL,這樣所有人都可以訪問到該文件。

  接着的兩行創建一個ACE,並且將它加入到ACL中。對於指定的帳號名,LookupAccountName函數返回一個SID。LookupAccountName函數將在系統或者本地系統中查找特定的帳號。如果在本地找不到,它將會在域
控制器或者信任的域控制器中找。該函數返回帳號的SID,如果SID是由域控制器得到的,它還會返回一個域名,以及一個枚舉值,該值用來指示帳號的類型:


SidTypeUser 
SidTypeGroup 
SidTypeDomain 
SidTypeAlias 
SidTypeWellKnownGroup 
SidTypeDeletedAccount 
SidTypeInvalid 
SidTypeUnknown 



  SID是一個安全標識符,它唯一標識系統中的一個用戶或者一個組。

  由LookupAccountName函數返回的SID被用在一個對AddAccessAllowedAce函數的調用中,該函數用來創建一個訪問允許(與訪問拒絕相對)ACE,並且將它加入到當前爲空的ACL中。

  AddAccessAllowedAce 函數創建該SID的ACE和指定的訪問掩模,並且將它加入到指定的ACL中。GENERIC_READ訪問掩模爲文件加入讀權限。

  現在ACL中包含了一個ACE,並且指定了“guest”用戶可以讀取該文件。這個ACL需要使用SetSecurityDescriptorDacl函數來放入到安全描述器的Discretionary ACL中。

  現在安全描述器中包含了一個有效的DACL,其中有一個ACE。程序將這個安全描述器放到一個安全屬性結構體中,並且將它傳送給CreateFile函數。

  如果你將前面的三行代碼註釋掉,並且在調用SetSecurityDescriptorDacl時,將DACL的pacl用NULL代替,這時任何人都可以訪問該文件。沒有DACL意味着任何人可以訪問該文件。

  編譯並運行以上的代碼。在你運行前,你要確保程序中指定的文件名在系統中並不存在。通過文件管理器的安全編輯器查看該新文件時,你將會發現它的權限與代碼中設置得一樣。

  你可以很容易地修改這些代碼,以加深對安全描述器的瞭解。例如,你可以嘗試給某個組寫的權限,或者給DACL加入幾個ACE,或者使用AddAccessDeniedAce創建一個訪問拒絕ACE。要確保訪問拒絕ACE放在訪問允許ACE的前面。使用SetSecurityDescriptorOwner函數來修改安全描述器中的擁有者。
發佈了80 篇原創文章 · 獲贊 8 · 訪問量 34萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章