解決方案
將FSO組件和刪除或改名的方式我們不再過多的加以說明了,這一類的解決方法網絡上已經有很多文章介紹了。
另外還有一種關于ASP的FSO組件漏洞的相應解決方案,即根據用戶設置權限。在IIS里,可以設置每個站點的匿名訪問所使用的帳號,默認為IUSR_ HostName,這一方法的原理就是針對每一個共享主機用戶分別設置一個Windows帳號,如IUSR_HostName1,IUSR_ HostName 2等,然后將每一個用戶限制在各自的Web目錄下。
我們仔細的研究一下這種方案,可以發現這個方案無法真正實現安全。因為系統運行ASP時并不是使用的IUSR_ HostName帳號,而是IWAM_ HostName帳號,就象在ASP.NET中使用的用戶ASPNET一樣。也就是說每個ASP程序所擁有的權限并不是IUSR_ HostName的權限,而是IWAM_HostName用戶的權限。這樣的方法無法真正的將每個共享主機用戶的文件系統訪問權限限制在各自的虛擬站點中,每個用戶仍然可以訪問別人的代碼。所以這種方法在ASP.NET中無法真正實現用戶之間的安全性。
在ASP.NET中相應的運行ASP.NET程序的帳號為ASPNET,和上面所說的ASP中的解決方案類似,我們只能限制此用戶不能訪問系統目錄等其他目錄,但是無法防止用戶訪問其他共享主機用戶的程序代碼,無法從根本上杜絕這種問題。
那么,有沒有真正的解決方案了呢?
有!這就是.NET Framework 的新特性――代碼訪問安全性
為了更好的理解這一問題的解決方法,我們需要先介紹一下.NET Framework的安全機制。然后再結合我們的實際問題來討論解決方案。
為了解決安全問題,.NET Framework提供了一種稱為代碼訪問安全性的安全機制。代碼訪問安全性允許根據代碼的來源和代碼的標識等屬性將代碼設置為不同級別的信任代碼,同時還詳細定義了不同級別的對代碼的信任,從而可以詳細的對代碼設置各自的權限而不是將最大權限賦給所有的代碼。使用代碼訪問安全性,可以減小惡意代碼或各種錯誤的代碼帶來的嚴重的系統安全性問題的可能性。您可以設置允許代碼執行的一組操作,同樣可以設置永遠不允許代碼執行的一組操作。
實現代碼訪問安全性的基礎就是JIT(運行時編譯)和IL(中間代碼)。所以所有以公共語言運行庫為目標的托管代碼都會受益于代碼訪問安全性。非托管代碼則無法完全使用代碼訪問安全性。
下面我們將介紹一下代碼訪問安全性實現的各種功能:
代碼訪問安全性是控制代碼對受保護資源和操作的訪問權限的一種機制。在 .NET Framework中,代碼訪問安全性執行下列功能:
· 定義權限和權限集,它們表示訪問各種系統資源的權限。
· 使管理員能夠通過將權限集與代碼組關聯來配置安全策略。
· 使代碼能夠請求運行所需權限以及其他一些有用的權限,以及指定代碼絕對不能擁有哪些權限。
· 根據代碼請求的權限和安全策略允許的操作,向加載的每個程序集授予權限。
· 使代碼能夠要求其調用方擁有特定的權限。
· 使代碼能夠要求其調用方擁有數字簽名,從而只允許特定組織或特定站點的調用方來調用受保護的代碼。
· 通過將調用堆棧上每個調用方所授予的權限與調用方必須擁有的權限相比較,加強運行時對代碼的限制。
為了確定是否已授予代碼相應的權限,.NET運行庫的安全系統將遍歷整個調用堆棧,將每個調用方所授予的權限與目前要求的權限相比較。如果調用堆棧中的任何調用方沒有要求的權限,則會引發安全性異常,并會拒絕訪問和相應的操作。堆棧步旨在防止引誘攻擊;在這種攻擊中,受信程度較低的代碼調用高度信任的代碼,并使用高度信任的代碼執行未經授權的操作。在運行時要求所有調用方都擁有權限將影響性能,但對防止代碼遭受攻擊至關重要。若要優化性能,可以使代碼執行較少的堆棧步;但是,任何時候這樣做時均必須確保不會暴露安全缺陷。
還存在另外一種代碼訪問安全性的常見用途,即應用程序將控件從網絡 Web 站點直接下載到客戶端,這種方式的代碼安全性也是可以在客戶端進行設置的,根據簽名等數據權限證書來確定是不是可以允許下載的控件運行。這種方法類似于ActiveX的安全性設置,但是比之在設置權限更加詳細和強大。同JAVA APPLET的沙箱安全機制相比,.NET 的客戶端控件可以在本地簡單設置后訪問客戶端的各種資源。由于這一方面的用途不是我們的重點,所以我們在這里就不再更詳細的討論其用途及其實現原理了。
下面我們就談談如何應用這一安全特性來解決ASP.NET中存在的系統安全漏洞。由于我們介紹的系統是共享主機,所以有其特殊性,即系統管理員無法事先給所有的代碼賦予相應的權限,因為每個用戶都可能有各種權限要求,并且這些要求特殊權力的代碼在使用中都可能出現的,所以在權限管理上隨時都有各種要求。
因此在權限設置方面,不僅僅是管理員設置,也包括了各個共享主機用戶的權限請求,這也正是安全代碼機制的一個重要部分。
請求權限是您讓運行庫知道代碼執行有哪些操作權限的方法。通過將屬性(聲明式語法)放到代碼的程序級范圍來為程序集請求權限。
請求內置權限的代碼示例:
//The attribute is placed on the assembly level. using System.Security.Permissions; [assembly:PermissionSetAttribute(SecurityAction.RequestMinimum, Name = "FullTrust")] |
將此段代碼放在程序的開始部分(namespace聲明之前),在編譯時就會將請求的權限存儲在程序集清單中。加載時,運行庫檢查權限請求,并應用安全策略規則來確定授予程序集哪些權限。
雖然我們編寫的大部分代碼都沒有請求權限,其實不管是共享主機形式還是獨立服務器形式都應該請求權限,這是因為請求權限有助于確保只將代碼需要的權限授予代碼。如果沒有授予代碼額外權限,即使某些惡意代碼想利用您的代碼來進行安全性破壞,它也無法操作沒有賦給您自己代碼相應權限的額外系統資源。您只應該請求代碼需要的那些權限,而不應請求更多權限。
代碼請求權限之后,系統管理員可以使用"權限查看"工具 (Permview.exe,位于您的.NET Framework的目錄的bin目錄下) 來檢查您的程序集并根據其他條件來設置安全策略以決定是否給您的代碼所請求的相應權限。如果您不顯式地在代碼中請求應用程序需要的權限,那么管理員將很難管理您的應用程序。在權限管理嚴格的主機上,將無法實現您的代碼所要求的功能。
請求權限會通知運行庫應用程序正常運行需要哪些權限,或具體不需要哪些權限。在.NET Framework安裝后的默認狀態下,所有代碼都是FullTrust(完全信任)的。這時是不需要申請任何權限的,但是管理員一旦修改了代碼安全,我們使用的磁盤訪問就要受到限制了,這是就需要申請相應的權限了。我們上邊介紹的文件管理代碼就需要具有本地硬盤讀寫操作的能力,則應用程序必須擁有 FileIOPermission。如果代碼不請求 FileIOPermission,在本地安全設置不允許應用程序擁有此權限的主機上,在應用程序嘗試磁盤操作時就會引發安全性異常。即使應用程序能夠處理此異常,也不會允許它操作磁盤。當然,如果您的代碼不訪問受保護的資源或執行受保護的操作,則不必請求任何權限。例如,如果代碼只根據向它傳遞的輸入來計算結果而不使用任何資源,則不必請求權限。如果您的代碼訪問受保護的資源但未請求必要的權限,則仍可能允許它執行,但如果它嘗試訪問某種資源而它又沒有必要的權限,則可能在執行過程中失敗。
系統管理員在得到了用戶的權限申請后,可以根據情況考慮是否賦予用戶相應的權限,在這里我們來看一下相應代碼權限設置的具體方法。
在我們安裝成功.NET Framework之后,在Windows 2000 Server的管理工具里多了兩項管理工具: Microsoft .NET Framework Configration和Microsoft .NET Framework Wizards。這兩種管理工具要實現的功能差不多,只不過Microsoft .NET Framework Wizards是通過向導方式設置,如果您對于.NET Framewrk的安全性操作不是很熟悉的話,可以使用向導根據系統提示一步步的來設置相關的權限。
 Microsoft .NET Framework Wizards界面 |
 Microsoft .NET Framework Wizards界面 |
使用Microsoft .NET Framework Wizards可以簡單的設置.NET Framework的權限。但是我們為了更好的管理各個代碼的權限,還是使用Microsoft .NET Framework Configuration來詳細的設置我們所需的權限。
 (Microsoft .NET Framework Configuration主界面) |
在Microsoft .NET Framework Configuration中可以設置所有關于.NET Framework的屬性。
點擊我的電腦,打開下拉菜單,我們可以看到程序集緩存、已配置程序集、遠程處理服務、運行庫安全策略、應用程序等五項。運行庫安全策略設置是我們這篇文章的重點。
我們可以先查看一下程序集緩存,在這里我們可以看到所有的全局程序集緩存,全局程序集緩存中存儲了專門指定給由計算機中若干應用程序共享的程序集。在這里我們可以發現我們可以使用的所有的程序集,同時也可以添加和刪除某些程序集。詳細操作請參見.NET Framework SDK文檔。
我們在這里主要討論的是運行庫安全策略。在此策略中,按層次結構由高到低分為四個級別,即:企業、計算機、用戶、應用程序。在計算權限授予時,運行庫從該層次結構的頂部開始,然后向下進行計算。較低的策略級別不能對在較高級別上授予的權限進行增加,但是可以使權限減少。這就是說如果我們將計算機策略設置為較小的權限時,可以不必更改企業策略就可以使設置的權限生效,也就是說權限檢查的順序是從低級別到高級別,只有在低級別中不存在的設置才會檢查上一級的設置。默認情況下,用戶策略和應用程序域策略的限制性小于計算機策略和企業級策略。大部分默認策略存在于計算機級別。所以我們需要將默認安裝的主機的權限在計算機級別上進行修改,修改的內容根據主機是不是共享主機,主機應用的其他不明代碼的可能性來設置。如果是我們討論的共享主機的話,在計算機級別上就盡量將權限設的小一些,為了避免我們討論的文件系統安全問題,一定要注意權限中的本地磁盤訪問權限。
我們打開計算機策略設置可以發現幾個默認的代碼組、權限集和策略程序集。
根據需要,我們可以添加代碼組和自定義的權限集。
在添加代碼組的時候可以選擇幾種條件,主要的條件類型:默認為All Code、應用程序目錄、哈希、強名稱、作者、站點等。
對于我們所要討論的共享主機,我們需要將My_Computer_Zone下的All Code的權限更改為不能進行磁盤讀寫,在更改之前,我們需要先定義一個權限集。這一權限集的作用就是將我們需要點擊權限集,右鍵快捷菜單中選擇新建,會出現一個創建權限集的窗口,這里需要給我們新建的權限集命名。下一步就是將單個權限分配給權限集。如下圖所示。
 |
在這里我們可以給這個新建的權限集賦予一個的系統權限,如上圖所示,可用的權限包括:目錄服務、DNS、事件日志、環境變量、文件IO、OLEDB數據庫操作、注冊表等等。我們主要要說明的是文件IO操作,其他的權限操作可以根據自己的需求來設置。這里我們就不再說明了。
在文件IO的權限設置中我們可以自定義針對每一個目錄的權限,這里包括讀、寫、追加、路徑盤等操作,在這里我們可以將我們需要的目錄權限添加到列表中。因為我們是利用這一權限使所有沒有配置權限的代碼不可以進行文件IO操作,所以我們不強文件IO添加到分配的權限中。
新建了這一權限集后,我們更改一下默認設置,即將All Code的權限設置為此新建的權限集,也就是說所有沒有在此定義代碼都不能訪問文件IO系統。
這里需要注意一件事情,因為Microsoft .NET Framework Configuration本身也需要文件IO權限,如果沒有單獨分配給Configuration一個文件IO操作權限的話,那么您就不能再次使用Configuration來設置權限了,只能重新安裝.NET Framework了。所以我們需要將FullTrust權限分配給Configuration所使用的Dll,即mscorcfg.dll。在添加時,成員條件可以選擇強名稱,使用"導入",到winnt/window .net/framework/versionnumber/下選擇mscorcfg.dll。如果需要運行其他配置程序,還需要設置相應的權限,這些系統程序一般都在系統程序集緩存中。
這樣我們就完成了一個簡單的設置,可以防止任何未經驗證的代碼訪問文件IO系統。這樣就從根本上防止了磁盤惡意操作。
如果您今后需要利用這一功能或者有共享主機用戶需要使用文件IO功能,那么您可以在Microsoft .NET Framework Configuration中將其加入代碼,如果不能使其使用其他功能,可以僅僅設置一個只具有文件IO權限的權限集。如果是共享主機用戶您還可以給他分配直接到其所使用的目錄的全部讀寫權限,對于他的日志文檔,您可以將讀功能分配給用戶。通過上邊新建權限集時我們可以發現:權限集可以規定到每一個目錄的讀寫權限,所以可以將用戶鎖定于其可以使用的目錄中。當然對于共享主機提供商來說,最好的方法就是自己實現這些功能,然后配置權限系統使用戶使用共享主機提供商的程序來實現他們的正常操作,而避免了惡意文件操作。
需要注意的是如果分配給每一個單獨的程序相應的權限時,我們最好使用強名稱這一方式或者其他的可驗證方式,強名稱由程序集的標識--其簡單文本名稱、版本號和區域性信息(如果提供)--加上公鑰和數字簽名組成。這就需要我們使用Sn.exe 來設置密鑰、簽名和簽名驗證。強名稱保證了程序是開發人員開發的并且沒有被改動。
在進行上面的設置之后,管理員可以根據用戶的各種需求來設置不同的代碼集和權限集。
我們已經簡單的介紹了一下ASP.NET中關于文件IO系統的漏洞的防治方法,這一方法有些繁瑣,但是卻可以從根本上杜絕一些漏洞,由于.NET的JIT(運行時編譯)和IL(中間語言),.NET可以在程序編譯時檢查程序的安全性設置,所以能從根本上防止一些非法訪問。.NET的代碼安全性的內容很全面,我們討論的只是很少的一部分,更多的功能需要大家共同來探索、學習。