文章目錄
Visual Basic .NET 和 Visual C# .NET 程式員需要解決的安全問題
Robin Reynolds-Haertle
Visual Studio Team
Microsoft Corporation
2002 年 1 月
摘要:本文著重討論了 Visual Basic .NET 和 Visual C# .NET 開發人員在開始使用 .NET 架構時需要解決的主要安全問題。此概述討論了 Windows 應用程式和 Web 應用程式,以及開發過程的實現、調試和部署階段。
本文適用於 Visual Studio .NET 和 .NET 架構的最終版本。如果您使用的是預發布版本,則其中應用程式的運行可能與本文所討論的略有不同。
目錄
- 簡介
- 程式碼存取安全性
- 完全信任
- 部分信任
- 部分信任環境的開發
- 測試
- 其他資源
- Web 應用程式
- 動態發現
- 身分識別驗證、類比和委託
- ASPNET 進程標識
- 在 ASPNET 標識下運行時保護檔案資源的安全
- 使用 ASPNET 標識進行調試
- Visual Studio .NET 開發環境中的安全機制
- 總結
簡介
與早期版本的 Visual Studio 相比,Microsoft Visual Studio .NET 為應用程式的運行提供了更好的安全控制。.NET 架構提供了更多的控制,同時也要求您承擔更多的編程責任。在為使用者建立友好易用的應用程式時,您需要解決一些安全問題。
通常在以下三種情況下需要解決安全問題:
- 運行您的應用程式的使用者可能拒絕該應用程式的許可權,因為應用程式所啟動並執行位置已被指定為拒絕該使用者訪問某些系統資源。例如,使用者可以通過配置通用語言執行平台來拒絕儲存在網路磁碟機上的所有應用程式的檔案許可權。您在編寫代碼時應注意此問題,並且應編寫代碼對這種拒絕作出恰當的回應。
- 需要防止從您的 Web 服務器訪問 Web 應用程式的使用者在伺服器上運行惡意代碼或破壞資料。
- Visual Studio 的設定方式將或多或少地使伺服器面臨受到惡意代碼攻擊的危險。
程式碼存取安全性
程式碼存取安全性是 .NET 架構的一個系統,它通過控制碼的執行來控制對資源的訪問。這種安全功能獨立於作業系統提供的安全性,並且是對作業系統提供的安全性的補充。當使用者運行您的應用程式時,應用程式將由 .NET 通用語言執行平台分配到五個地區之一。這五個地區是:
- 我的電腦 - 使用者電腦上的應用程式。
- 本地 Intranet - 使用者的 Intranet 上的應用程式。
- Internet - 來自 Internet 的應用程式。
- 可信網站 - 來自由 Internet Explorer 定義為“可信”網站的應用程式。
- 不可信網站 - 來自由 Internet Explorer 定義為“受限”網站的應用程式。
上述每個地區都由系統管理員設定了特定的存取權限。可以將每個地區的安全層級設定為完全信任、中級信任、低級信任或不信任。信任層級定義了應用程式可以訪問的資源。地區與其他安全憑證(例如發行者、強式名稱、Web 網站以及代碼的 URL)一起確定在運行時授予該代碼的許可權。您無法控制使用者電腦上的安全設定,但您的應用程式在運行時仍會受到即時設定的限制。這就意味著應用程式可能會被拒絕訪問某些特定資源。例如,應用程式可能需要將資料寫入檔案,但使用者的系統將通過引發異常而拒絕在運行時進行寫入訪問。有關安全憑證的詳細資料,請參閱 Evidence(英文)。
您的工作就是開發應用程式來處理這種情況。這並不表示讓您的應用程式用另外一種方法來寫入資料,而是說您的應用程式應該預計到可能無法寫入資料,然後對這種可能性作出響應。您可能需要使用更多的異常處理(Visual Basic 中的 Try...Catch 或 C# 中的 try...catch)或 System.Security.Permissions 命名空間中的某些對象,以使應用程式代碼更加可靠。本文後面“部分信任環境的開發”一節對這些方法進行了簡要說明。
地區的安全層級可以通過隨 .NET 架構一起安裝的“管理工具”來進行設定。有關在電腦上設定地區安全層級的詳細資料,請參閱 Administration Tools(英文)。
完全信任
開發人員通常在完全信任環境中工作。他們將原始碼存放在硬碟上,並在用於開發的電腦上對其應用程式進行測試。在這種完全信任環境中,開發人員編譯的任何代碼都可以在本機電腦上運行。由於本機電腦被預設定義為完全信任環境,因此不會出現安全異常。
部分信任
部分信任是指完全信任地區以外的所有地區。部署應用程式時,應用程式可能會移至新的地區,而新地區可能不完全信任應用程式。在部分信任環境中運行代碼的兩種最常見的情況是:
- 運行從 Internet 下載的代碼。
- 運行駐留在網際網路共用位置 (Intranet) 的代碼。
在部分信任地區中可能會被拒絕訪問的資源樣本包括:
- 檔案 I/O,包括檔案的讀取、寫入、建立、刪除或列印。
- 系統組件,如註冊表值和環境變數。
- 伺服器組件,包括目錄服務、註冊表、事件記錄、效能計數器和訊息佇列。
在部分信任環境中哪些內容是不允許的呢?這不太容易確定。.NET 架構中的每個類以及每個類中的每種方法都有一個安全屬性,用於定義運行該方法所需的信任層級,並且正是由於這些安全功能,使得在運行時可能無法訪問該屬性。地區層級並不只是信任層級到屬性的簡易對應,而是一個授予特定類和方法的特定許可權的集合。您的應用程式無法只是簡單地查詢信任層級然後就可以預計哪些資源不可用。您可以確定應用程式是否在完全信任環境中運行。在下一節“部分信任環境的開發”中,我們將介紹一種方法。
部分信任環境的開發
本節簡要介紹了安全問題可能會對編寫的代碼產生什麼樣的影響。部分信任環境的開發沒有單一的解決方案。您的解決方案取決於您所編寫的應用程式。此外,由於信任層級在應用程式的執行過程中可能會發生變化,因此不能僅測試現有的信任層級,然後就繼續執行。
開發部分信任地區的第一步是編寫能夠識別即將發生安全異常的代碼。請注意以下代碼:
' Visual BasicPublic
Sub MakeABitmap()
Dim b As Bitmap = New Bitmap(100, 100)
' 此處的代碼將以位元影像格式繪製一張漂亮的圖片
b.Save("c:\PrettyPicture.bmp")
End Sub
// C#
public void MakeABitmap()
{
Bitmap b = new Bitmap(100, 100);
// 此處的代碼將以位元影像格式繪製一張漂亮的圖片
b.Save("c:\\PrettyPicture.bmp");
}
如果項目和項目程式集儲存在您電腦的硬碟上,並且您是電腦 Administrators 組的成員,則此方法在運行時不會引發異常。如果將此應用程式部署到您的 Intranet,則當應用程式試圖儲存位元影像對象時,將引發 System.Security.SecurityException(請參閱 SecurityException Class [英文])。如果此代碼周圍沒有 Try...Catch(在 Visual Basic 中)或 try...catch(在 C# 中)塊,則應用程式將因異常而終止。這會令使用者感到不滿意。如果您添加異常處理代碼,應用程式就能夠:
- 警告使用者應用程式無法完成所有需要完成的任務。
- 清除所有現有對象,以便 catch 塊後面的代碼能夠成功運行。
您可以按如下所示修改儲存位元影像的代碼。添加的代碼將警告使用者該檔案因安全性被拒絕而未能儲存,從而將安全性失敗與檔案 I/O 失敗(例如不正確的檔案名稱)區分開來。這種方法不會產生任何安全性漏洞。使用者應修改安全設定以信任您的應用程式,否則應用程式將不會運行。
' Visual BasicPublic
Sub MakeABitmap()
Dim b As Bitmap
Try
b = New Bitmap(100, 100)
b.Save("c:\PrettyPicture.bmp")
Catch ex As System.Security.SecurityException
' 告知使用者儲存失敗。
MessageBox.Show("拒絕授予儲存該檔案的許可權," & _
"未儲存此位元影像。")
Catch ex As System.Exception
' 此處對其他異常作出反應。
MessageBox.Show(ex.Message)
End Try
End Sub
// C#
public void MakeABitmap()
{
Bitmap b = null;
try
{
b = new Bitmap(100, 100);
b.Save("c:\\PrettyPicture.bmp");
}
catch (System.Security.SecurityException ex)
{
// 告知使用者儲存失敗。
MessageBox.Show("拒絕授予儲存該檔案的許可權," +
"未儲存此位元影像。"); }
catch (System.Exception ex)
{ // 此處對其他異常作出反應。
MessageBox.Show(ex.Message);
}
}
使用 System.Security.Permissions(英文)命名空間中的類、屬性和枚舉,可以對應用程式中安全任務進行更多的控制。如果您在編寫可從其他應用程式調用的庫,則可以讓庫驗證調用代碼的許可權。例如,您只需在代碼檔案的頂部添加以下程式集層級的屬性。載入該程式集時,運行時將驗證許可權。如果運行時拒絕所請求的許可權,程式集將無法載入並且將引發一個安全異常。如果向獨立的應用程式添加此屬性,則應用程式可能不會運行。如果此屬性出現在類庫中,則可能不會在運行時載入該庫。您需要在調用此類庫的代碼中添加 try/catch 塊。
' Visual Basic
<Assembly: System.Security.Permissions.FileIOPermissionAttribute
( _SecurityAction.RequestMinimum,
Write:="c:\PrettyPicture.bmp")>
// C#
[assembly: System.Security.Permissions.FileIOPermissionAttribute
(SecurityAction.RequestMinimum, Write="c:\\PrettyPicture.bmp")]
您也可以專門向運行時請求許可權,下面的樣本中使用了 Demand 方法。運行時可能允許或拒絕該請求。拒絕請求是通過引發安全異常來實現的。您可以按如下所示重新編寫代碼,以明確請求寫入位元影像檔案的許可權:
' Visual BasicPublic
Sub MakeABitmap()
Dim filename As String = "c:\PrettyPicture.bmp"
Dim permission As FileIOPermission = _
New FileIOPermission(FileIOPermissionAccess.Write, _
filename)
Dim b As Bitmap = Nothing
Try
b = New Bitmap(100, 100)
permission.Demand()
b.Save(filename)
Catch ex As System.Security.SecurityException
' 告知使用者儲存失敗。
MessageBox.Show("拒絕授予儲存該檔案的許可權," & _
"未儲存此位元影像。")
Catch ex As System.Exception
' 此處對其他異常作出反應。
MessageBox.Show(ex.Message)
End Try
End Sub
// C#
using System.Security.Permissions;
public void MakeABitmap()
{
string filename = "c:\\PrettyPicture.bmp";
FileIOPermission permission = new
FileIOPermission(FileIOPermissionAccess.Write,
filename);
Bitmap b = null;
try
{
b = new Bitmap(100, 100);
permission.Demand();
b.Save(filename);
}
catch
(System.Security.SecurityException ex)
{
// 告知使用者儲存失敗。
MessageBox.Show("拒絕授予儲存該檔案的許可權," +
"未儲存此位元影像。"); }
catch (System.Exception ex)
{ // 此處對其他異常作出反應。
MessageBox.Show(ex.Message);
}
}
測試
開發部分信任地區的第二步是在多個環境中進行測試,尤其是在您的 Intranet 和 Internet 上。這將強制引發安全異常。