日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

ASP.NET虚拟主机的重大安全隐患

發布時間:2023/11/27 生活经验 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ASP.NET虚拟主机的重大安全隐患 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

作者:秦海鵬??來自: yesky

說明:本文中所有程序均在Windows 2000 Server中文版 + SP2上編譯運行無誤
開發環境:.Net 框架1.0 Version 1.0.3705

  一、ASP.NET虛擬主機存在的重大隱患

  我曾經在WWW.BRINKSTER.COM申請了一個免費的ASP.NET空間,上傳了兩個程序,其中一個查看目錄和文件的程序證明我的判斷:ASP共享空間服務器存在的一個安全問題,在 ASP+ 共享空間服務器中依然存在并且變得更加難以防范!通過這個程序我可以瀏覽所有用戶的ASP+程序,可以查看服務器的系統日志……,當然,如果我想刪除什么的話也不會有什么問題。為了讓大家更清楚地了解這一問題,我們有必要簡單介紹一下ASP中就已經存在的這一問題。

  ASP中常用的標準組件:FileSystemObject,這個組件為 ASP 提供了強大的文件系統訪問能力,可以對服務器硬盤上的任何有權限的目錄和文件進行讀寫、刪除、改名等操作。FSO對象來自微軟提供的腳本運行庫scrrun.dll中。

  使用下面的代碼就可以在ASP中創建一個FSO對象:

  Set fso = CreateObject("Scripting.FileSystemObject")

  我們使用fso對象包含的屬性和方法,如Drive、Drives、Folder、Floders、File、Files等對服務器的磁盤、目錄和文件進行讀、寫、刪除等操作。這一強大的文件系統訪問能力給ASP共享空間提供者帶來了嚴重的安全問題,很多ASP空間的管理員都刪除此組件或將這個組件改名以避免用戶使用這一標準組件。刪除組件或組件改名確實是一個簡單的方法并且也很有效,但是卻使廣大用戶無法使用它的強大的功能。網絡上還有一種看起來很美的方案,它允許用戶使用 FileSystemObject 組件又不影響服務器的安全,即對每一個用戶都設置一個獨立的服務器用戶和單個目錄的操作權限。但是這種方法是有問題的。因為ASP和ASP.NET中在這方面的問題十分類似,所以我們將在ASP.NET的相應解決辦法部分詳加說明。

  在ASP.NET中我們發現這一問題仍然存在,并且變得更加難以解決。這是因為.NET中關于系統IO操作的功能變得更加強大,而使這一問題更嚴重的是ASP.NET所具有的一項新功能,這就組件不需要象ASP那樣必須要使用regsvr32來注冊了,只需將Dll類庫文件上傳到bin目錄下就可以直接使用了。這一功能確實給開發ASP.NET帶來了很大的方便,但是卻使我們在ASP中將此dll刪除或者改名的解決方法失去效用了,防范此問題就變得更加復雜。在討論解決方案之前,我們先來看一下怎么來實現上述的危險的功能。

二、文件系統操作示例

  在我們編寫代碼之前,有必要了解一下我們需要用到的幾個主要的類。這幾個類都在System.IO名稱空間下,System.IO 名稱空間包含允許在數據流和文件上進行同步和異步讀寫的類。

  在整個應用程序的開始部分我們需要了解一下服務器的系統信息,這就需要用到System.Environment類,該類提供有關當前環境和平臺的信息以及操作它們的方法。我們通過System.Environment類可以得到系統的當前目錄和系統目錄,這可以使我們更快的發現幾個關鍵的目錄;我們還可以通過獲取運行當前進程的用戶名來幫助我們了解ASP.NET程序運行所使用的用戶,進一步設置用戶權限以避免這一安全問題。

  我們還要使用System.IO名稱空間的其他幾個類是:

  System.IO.Directory:提供用于創建、移動和枚舉通過目錄和子目錄的靜態方法的類

  System.IO.File:提供用于創建、復制、刪除、移動和打開文件的靜態方法的類

  System.IO.FileInfo:提供創建、復制、刪除、移動和打開文件的實例方法的類

  System.IO.StreamReader:實現一個 TextReader,使其以一種特定的編碼從字節流中讀取字符。

  每個我們所使用的類的屬性和方法的具體用法我們將以代碼注釋的方式在程序中加以說明。

  System.IO名稱空間在 .NET FRAMEWORK提供的mscorlib.dll中,在使用VS.Net編程之前需要將此Dll引用到此項目中。

  我們所編寫的程序都使用了Codebehind方式,即每一個aspx程序都有一個對應的aspx.cs程序,aspx程序中只是寫與頁面顯示相關的代碼,所有邏輯實現的代碼都放在相應的aspx.cs文件中,這樣就可以更好得做到顯示與邏輯的分離。由于我們的目的不是討論Codebehind技術,所以就不在對此多加討論了。

  在這篇文章里,我們只介紹幾個主要的類及其關鍵方法的用法,詳細程序請查看附帶的源代碼。

  程序一:顯示服務器的當前信息和全部邏輯驅動器的名稱的程序listdrivers.aspx

  主要方法1:我們使用 GetSysInf() 方法來得到服務器的當前環境和平臺的信息

//獲取系統信息的方法,此方法在listdrivers.aspx.cs文件中
public void GetSysInf () {
//獲取操作系統類型
qDrives = Environment.OSVersion.ToString();
//獲取系統文件夾
qSystemDir = Environment.SystemDirectory.ToString();
/*獲取映射到進程上下文的物理內存量,通過這一內存映射量可以了解ASP.NET程序在運行時需要多少系統物理內存,
有助于更好的規劃我們的整個應用,因為物理內存量是以Byte為單位的,所以我們將此數值除以1024,可以得到單位為KB的物理內存量*/
qMo = (Environment.WorkingSet/1024).ToString();
//獲取當前目錄(即該進程從中啟動的目錄)的完全限定路徑
qCurDir = Environment.CurrentDirectory.ToString();
//獲取主機的網絡域名
qDomName = Environment.UserDomainName.ToString();
//獲取系統啟動后經過的毫秒數
qTick = Environment.TickCount;
//計算得到系統啟動后經過的分鐘數
qTick /= 60000;
//獲取機器名
qMachine = Environment.MachineName;
//獲取運行當前進程的用戶名
qUser = Environment.UserName;
/*檢索此計算機上格式為"<驅動器號>:"的邏輯驅動器的名稱,返回字符串數組,這是下一步操作的關鍵所在*/
achDrives = Directory.GetLogicalDrives();
//獲取此字符串數組的維數,確定有多少個邏輯驅動器
nNumOfDrives = achDrives.Length;
}


  系統信息不需要進行操作,我們簡單的用asp:Label將他們顯示出來就行了。邏輯驅動器的個數在不同的服務器上是不定的,所以用不定長數組保存邏輯驅動器的名稱,而且邏輯驅動器的名稱也是我們下一步瀏覽目錄和文件的基礎,故我們采用了數據網格DataGrid來顯示和處理它。

  顯示和處理邏輯驅動器名稱的DataGrid的代碼(代碼在listdrivers.aspx文件):

<asp:DataGrid id="DriversGrid" runat="server" AutoGenerateColumns="false">
<Columns>
<asp:BoundColumn HeaderText="ID" DataField="ID" />
<asp:BoundColumn HeaderText="磁盤名" DataField="Drivers" />
<asp:HyperLinkColumn
HeaderText="詳細信息"
DataNavigateUrlField="Drivers" DataNavigateUrlFormatString="listdir.aspx?dir={0}"
DataTextField="Detail"
Target="_new" />
</Columns>
</asp:DataGrid>

  前兩個BoundColumn列都是顯示序號和實際邏輯驅動器名稱的,需要說明的是第三列,我們在進入各個邏輯驅動器顯示目錄和文件之前需要將所選擇的邏輯驅動器的名稱傳遞到顯示目錄的文件去,所以需要一個特殊的超級鏈接行HyperLinkColumn,我們將DataNavigateUrlField設置為數據源中要綁定到 HyperLinkColumn 中的超級鏈接的 URL 的字段,在此即邏輯驅動器名稱。然后將DataNavigateUrlFormatString設置為當 URL 數據綁定到數據源中的字段時,此HyperLinkColumn中的超級鏈接的 URL 的顯示格式,即要鏈接到的下一級處理頁面,在此為listdir.aspx?dir={用戶點擊行的邏輯驅動器名稱}
創建數據源的代碼(代碼在listdrivers.aspx.cs文件中):

//通過此方法返回一個集合形式的數據視圖DataView
ICollection CreateDataSource() {
//定義內存中的數據表DataTable
DataTable dt = new DataTable();
//定義DataTable中的一行數據DataRow
DataRow dr;
/*向DataTable中增加一個列,格式:DataColumn("Column", type)
Column為數據列的名字,type為數據列的數據類型*/
dt.Columns.Add(new DataColumn("ID", typeof(Int32)));
dt.Columns.Add(new DataColumn("drivers", typeof(string)));
dt.Columns.Add(new DataColumn("detail", typeof(string)));
//使用for循環將邏輯驅動器的名稱以行的形式添加到數據表DataTable中
for (int i = 0; i < nNumOfDrives; i++) {
//定義新行
dr = dt.NewRow();
//對行中每列進行賦值,注意要與上邊定義的DataTable的行相對應
dr[0] = i; //循環生成的序號
dr[1] = achDrives[i].ToString(); //邏輯驅動器的名稱
dr[2] = "查看詳情";
//向DataTable中添加行
dt.Rows.Add(dr);
}
//根據得到的DataTable生成自定義視圖DataView
DataView dv = new DataView(dt);
//返回得到的視圖DataView
return dv;
}

  我們通過這個方法得到了一個包含所有我們需要的數據的數據視圖DataView,我們只需要在此aspx頁的Page_Load方法中將此數據視圖綁定到DataGrid上就可以了。

  數據綁定代碼(代碼在listdrivers.aspx.cs文件中):

/* 設置DataGrid的數據源DataSource為我們從CreateDataSource()方法得到的數據視圖DataView */
DriversGrid.DataSource = CreateDataSource();
//將此DataGrid進行數據綁定
DriversGrid.DataBind();

  通過上邊介紹的幾種主要方法我們就實現了獲取系統信息和顯示所有邏輯驅動器名稱的功能,并且可以通過相應的鏈接進入下一個顯示目錄和文件名的程序listdir.aspx顯示該邏輯驅動器下的所有目錄和文件。

程序二:顯示目錄中所有子目錄和文件的程序listdir.aspx

  目錄下有子目錄和文件兩種形式,必須分別對待。我們調用此程序本身對子目錄進行列表顯示,而文件我們需要調用showfile.aspx程序對文件的屬性和內容進行顯示。并且兩者還有不同的刪除方法,所以我們在這里設置了兩個DataGrid,兩個DataTable,兩個DataView,分別處理和顯示目錄和文件。

  顯示和處理目錄和文件的DataGrid的代碼(代碼在listdir.aspx文件):

  顯示目錄或文件的序號和名稱的數據列類似于listdrivers.aspx程序中的相應代碼,這里就不再重復了。對于子目錄和文件分別有各自的處理頁面,所以需要導航到兩個不同的頁面,對于子目錄,我們繼續使用listdir.aspx程序對其下的子目錄和文件進行列表顯示:

<asp:HyperLinkColumn DataNavigateUrlField="DirName"
DataNavigateUrlFormatString="listdir.aspx?dir={0}"
DataTextField="DirDetail"
HeaderText="詳細信息"
Target="_new"
/>


對于文件,我們使用showfile.aspx程序顯示其屬性和內容:


<asp:HyperLinkColumn DataNavigateUrlField="FileName"
DataNavigateUrlFormatString="showfile.aspx?file={0}"
DataTextField="FileDetail"
HeaderText="詳細信息"
Target="_new"
/>

  在兩個DataGrid(DirGrid,FileGrid)中我們分別設置了兩個HyperLinkColumn列來導航到不同的處理頁面。

  在兩個DataGrid中我們都使用了一個刪除的按鈕列:

<asp:ButtonColumn HeaderText="刪除" 
Text="刪除"
CommandName="Delete"
/>

  由于添加、更新、刪除功能列都是DataGrid的默認模板列,所以可以在Vs.net中通過DataGrid的屬性生成器自動添加此列。

  獲取上一頁面所傳遞來的參數的代碼:

  因為在下面產生數據源的方法中需要使用由上一個頁面傳遞過來的參數來確定目錄和文件的名稱,所以在頁面的Page_Load方法里使用了下列代碼:

strDir2List = Request.QueryString["dir"];

  字符串strDir2List即傳過來的目錄名或文件名。

  因為我們使用了兩個DateGrid,就需要進行兩次數據綁定,就有兩個不同的生成數據源的方法。

  生成目錄數據網格(DirGrid)數據源的方法:

//通過此方法返回一個集合形式的數據視圖DataView,用來初始化子目錄的DataGrid
ICollection CreateDataSourceDir() {
dtDir = new DataTable();
DataRow dr;
//向DataTable中添加新的數據列,共四列
dtDir.Columns.Add(new DataColumn("DirID", typeof(Int32)));
dtDir.Columns.Add(new DataColumn("DirName", typeof(string)));
dtDir.Columns.Add(new DataColumn("DelDir", typeof(string)));
dtDir.Columns.Add(new DataColumn("DirDetail", typeof(string)));
//根據傳入的參數(目錄名)得到此目錄下所有子目錄名的字符串數組
string [] DirEntries = Directory.GetDirectories(strDir2List);
//使用foreach循環可以對未知長度的數組進行遍歷循環
foreach(string DirName in DirEntries){
dr = dtDir.NewRow();
dr[0] = i;//序號
dr[1] = DirName;//文件夾名稱
dr[3] = "刪除";
dr[3] = "查看詳情";
dtDir.Rows.Add(dr);
i++;
}
DataView dvDir = new DataView(dtDir);
//返回得到的數據視圖
return dvDir;
}
生成文件數據網格(FileGrid)數據源的方法:
//通過此方法返回一個集合形式的數據視圖DataView,用來初始化文件的DataGrid
ICollection CreateDataSourceFile() {
dtFile = new DataTable();
DataRow dr;
dtFile.Columns.Add(new DataColumn("FileID", typeof(Int32)));
dtFile.Columns.Add(new DataColumn("FileName", typeof(string)));
dtFile.Columns.Add(new DataColumn("DelFile", typeof(string)));
dtFile.Columns.Add(new DataColumn("FileDetail", typeof(string)));
//根據傳入的參數(目錄名)得到此目錄下所有文件名的字符串數組
string [] FileEntries = Directory.GetFiles(strDir2List);
foreach(string FileName in FileEntries){
dr = dtFile.NewRow();
dr[0] = i;
dr[1] = FileName;
dr[2] = "刪除";
dr[3] = "查看詳情";
dtFile.Rows.Add(dr);
i++;
}
dvFile = new DataView(dtFile);
return dvFile;
}

  我們編程實現了兩個DataSource只需在頁面的Page_Load方法里對兩個DataGrid進行數據綁定即可將得到的DataTable中的數據顯示在aspx頁面的DataGrid上。

  數據綁定代碼:

//對子目錄數據列表DirGrid進行數據源定義和數據綁定
DirGrid.DataSource = CreateDataSourceDir();
DirGrid.DataBind();
//對文件數據列表FileGrid進行數據源定義和數據綁定
FileGrid.DataSource = CreateDataSourceFile();
FileGrid.DataBind();

  通過我們上邊介紹的主要方法,我們實現了對某個邏輯驅動器或目錄中的所有子目錄和文件進行了列表顯示,并且可以根據顯示結果更進一步的瀏覽子目錄或者查看文件的屬性和內容提要。瀏覽子目錄仍然是通過listdir.aspx這個程序,沒有任何子目錄級別要求,沒有目錄深度限制。
刪除子目錄和文件的主要方法和代碼:

  在刪除子目錄時,我們需要用到Directory.Delete (string,bool)方法,此方法有兩種:

  1.public static void Delete(string);

  從指定路徑刪除空目錄。

  2.public static void Delete(string, boolean);

  刪除指定的目錄并(如果指示)刪除該目錄中的任何子目錄,將boolean設置為true的話,則刪除此目錄下的所有子目錄和文件,否則將boolean設置為false。

  在這里我們使用了第二種方法,如果選擇刪除的話,將刪除此目錄下的所有子目錄和文件。

  注意:Directory 類的所有方法都是靜態的,因而無需具有目錄Directory的實例就可被調用。

/*實現刪除子目錄的方法,此方法為VS.NET自動添加,注意DataGridCommandEventArgs e為DirGrid中 CommandName="Delete" 的
ButtonColumn的事件,通過此事件,我們可以得到是那一行的ButtonColumn按鈕列被點擊,進而確定我們需要刪除的子目錄的名稱*/
private void DirGrid_DeleteCommand(object source, System.Web.UI.WebControls.DataGridCommandEventArgs e){
/*定義一個單元格,e.Item為此事件所發生行的所有項目,e.Item.Cells[1]為整個行的第二個單元格的內容,在此DataGrid中為子目錄的名稱
*/
TableCell ItemCell = e.Item.Cells[1];
//得到此子目錄的名稱的字符串
string item = ItemCell.Text;
//刪除此子目錄
Directory.Delete(item,true);
//刪除后進行數據綁定以更新數據列表
DirGrid.DataBind();
}

  在刪除文件時,我們需要用到File.Delete(string path);

  注意:File 類的所有方法都是靜態的,因而無需具有目錄的實例就可被調用。

private void FileGrid_DeleteCommand(object source,
System.Web.UI.WebControls.DataGridCommandEventArgs e) {
TableCell ItemCell = e.Item.Cells[1];
//得到此文件名稱的字符串
string item = ItemCell.Text;
//刪除此文件
File.Delete(item);
//刪除后進行數據綁定以更新數據列表
DirGrid.DataBind();
}

  通過上邊的主要方法我們在頁面上實現了一個刪除某一個子目錄或者文件的功能,此功能在測試時需要慎重使用,一旦刪除無法通過常規方法恢復。其他如目錄或文件改名、修改內容等方法都可以在此程序基礎上添加相應的功能,實現方法也很簡單。各位愛好者可以通過添加相應功能,使之擴充為一個基于Web的服務器文件管理系統。我們也可以由此看到這個程序的危害性,一個沒有對此安全隱患采取防范措施的服務器的文件系統就都暴露在了使用此程序的用戶面前。
程序三:顯示文件屬性和內容的程序showfile.aspx

  在顯示屬性和內容時需要用到的兩個主要的類:

  System.IO.FileInfo:提供創建、復制、刪除、移動和打開文件的實例方法,并且幫助創建 FileStream 對象。

  System.IO.StreamReader:實現一個 TextReader,使其以一種特定的編碼從字節流中讀取字符。除非另外指定,StreamReader的默認編碼為 UTF-8,而不是當前系統的 ANSI 代碼頁。UTF-8 可以正確處理 Unicode 字符并在操作系統的本地化版本上提供一致的結果。

  Showfile.aspx頁面主要代碼:

<asp:Label id="FileDetail" runat="server"/>

  我們只是將文件的屬性信息和部分內容顯示在此Label上。所以沒有其他復雜的代碼。

  獲取文件信息和內容的主要代碼都在Page_Load方法中(代碼在showfile.aspx.cs文件中):

//接收傳入的參數,確定需要操作的文件名稱
strFile2Show = Request.QueryString["file"];
//根據文件名實例化一個FileInfo對象
FileInfo fi = new FileInfo(strFile2Show);
FileDetail.Text = "文件名:";
FileDetail.Text += strFile2Show+"<br>";
FileDetail.Text += "文件大小";
//獲得文件的大小,然后變換單位為KB
FileDetail.Text += (fi.Length/1024).ToString()+"K<br>";
FileDetail.Text += "創建文件時間:";
//獲得文件的創建日期
FileDetail.Text += fi.CreationTime.ToString();
FileDetail.Text += "上次訪問時間:";
//獲得文件的上次訪問日期
FileDetail.Text += fi.LastAccessTime.ToString()+"<br>";
FileDetail.Text += "上次寫入時間:";
//獲得文件的上次寫入日期
FileDetail.Text += fi.LastWriteTime.ToString()+"<br>";
//實例化一個StreamReader對象,用于讀取此FileInfo的內容
StreamReader FileReader = fi.OpenText();
//定義一個長度為1000的字符數組作為緩沖區
char[] theBuffer = new char[1000];
/*ReadBlock方法:從當前流中讀取最大數量的字符并從索引開始將該數據寫入緩沖區。
參數:
char[] buffer:方法返回時,包含指定的字符數組
int index:buffer 中開始寫入的位置
int count:最多讀取的字符數
*/
int nRead = FileReader.ReadBlock(theBuffer,0,1000);
FileDetail.Text += new String(theBuffer,0,nRead);
//關閉此 StreamReader 并釋放與之關聯的所有系統資源
FileReader.Close();

  到目前為止,我們實現了一個簡單的web頁面的服務器磁盤管理應用程序,可以查看、刪除目錄和文件。如果需要修改文件、新建文件和文件夾等功能,只需稍作修改,添加上相應的代碼就可以。由于我們只是通過這個程序說明服務器中存在的安全隱患,所以在這里就不再實現這些功能了。

  通過這三個簡單的程序,我想大家已經能夠清楚的認識到這一漏洞的危害性了,如果我們不加防范的話,其他用戶的程序就能被惡意使用此功能的用戶查看、刪除,服務器的系統日志、系統文件也沒有任何安全可言了。

?

解決方案

  將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的代碼安全性的內容很全面,我們討論的只是很少的一部分,更多的功能需要大家共同來探索、學習。

總結

以上是生活随笔為你收集整理的ASP.NET虚拟主机的重大安全隐患的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。