共用方式為


ADO.NET 安全程式碼撰寫方針

.NET Framework 提供許多有用的類別和服務,能讓開發人員撰寫安全的應用程式 (請參閱設定應用程式的安全性)。安全程式碼撰寫概觀提供各種方法概觀,供您設計與 .NET Framework 安全性系統搭配使用的程式碼。另外,也提供安全程式碼撰寫方針的連結,其中包含其他安全性主題的連結。此外,您必須遵循 ADO.NET 程式碼中的安全資料存取編碼實施方針,以避免被潛伏的攻擊者利用。常見的 ADO.NET 攻擊為攻擊者所發出的 SQL 插入攻擊,或根據應用程式傳回的例外狀況測知私人的資料庫資訊。使用參數型命令和有效的例外處理可阻止這類攻擊。

避免 SQL 插入攻擊

攻擊者將其他 SQL 陳述式,插入在資料來源或資料庫伺服器上進行處理的命令時,便會發生 SQL 插入。這些命令能擷取私人資訊,以及修改或破壞資料庫伺服器上的資訊。只要插入的 SQL 陳述式語法正確,就無法利用程式設計的方式偵測到伺服器端的遭到篡改。因此,您必須確保攻擊者無法將使用者輸入插入執行的命令中。請遵循下列方針,有助於阻止 SQL 插入攻擊:

  • 務必在最小權限的帳戶下執行。

  • 務必驗證來自外部來源的所有使用者輸入。

  • 務必將資料行值當做參數 (而非串連值) 傳遞。

SQL 插入攻擊範例

下列程式碼容易遭受 SQL 插入攻擊,因為它會接受來自 TextBox 控制項的任何使用者輸入,將其與 Transact-SQL 陳述式串連,並將串連的字串送至 SQL Server 進行處理。只要串連的 Transact-SQL 陳述式有正確的語法,且呼叫程式也有適當的使用權限,SQL Server 便會處理命令。藉由串連字串,攻擊者就可以利用您的應用程式,輸入可在伺服器上執行非預期命令的資料。

' Retrieve CustomerID to search for.
Dim ID As String = TextBox1.Text

' The following line of code allows for SQL injection attack.
Dim query As String = _
    "SELECT * FROM dbo.Orders WHERE CustomerID = '" & ID & "';"

' Code connecting to a data source has been omitted for brevity.
Dim cmd As SqlCommand = New SqlCommand(query, connection)
Dim reader As SqlDataReader = cmd.ExecuteReader()
reader.Close()
// Retrieve CustomerID to search for.
string ID =TextBox1.Text;

// The following line of code allows for SQL injection attack.
string query = 
    "SELECT * FROM dbo.Orders WHERE CustomerID = '" + ID + "';"

// Code connecting to a data source has been omitted for brevity.
SqlCommand cmd = new SqlCommand(query, connection);
SqlDataReader reader = cmd.ExecuteReader();
reader.Close();

在這個案例中,潛伏的攻擊者可針對 CustomerID 輸入 "ABCD';DELETE FROM Orders;--" 的值,其中 ABCD 是預期 WHERE 子句的有效值。ABCD 後面的單引號則會完成所要之查詢的 WHERE 子句,而分號則分隔第一個命令的尾端。DELETE FROM 陳述式開始新的命令,該命令即表示 SQL 插入攻擊。雙連字號字元序列 (--) 則是用來通知 SQL Server,接下來的所有內容都是註解且應該忽略,因此原始程式碼中串連的右單引號和分號 (+ "';") 不會產生語法錯誤。伺服器會處理下列字串,該字串由兩個不同的命令組成:

SELECT * FROM dbo.Orders WHERE CustomerID = 'ABCD';DELETE FROM Orders;--'

當 SQL Server 處理第一個命令時,會在 Orders 資料表中選取符合的記錄。當它處理第二個命令時,會刪除 Orders 資料表中的所有記錄。

SQL 插入攻擊可包含能捨棄資料表的語法,或在伺服器上執行其他命令的語法。損害的範圍取決於授與呼叫程序的使用權限。需要被授與資料表上的 SELECT 使用權限才能使用字串串連,因此,攻擊者能看到所有資料。

使用參數型命令

參數可方便您組織以 Transact-SQL 陳述式傳遞的值,或傳遞到預存程序的值。此外,若能確保從外部來源接受到的值只作為傳遞值,而不是 Transact-SQL 陳述式的一部份,則參數還可以防止 SQL 插入攻擊。因此,已插入值的 Transact-SQL 命令不會在資料來源執行。而是將其做為參數值單獨評估。如需在預存程序中驗證使用者輸入的詳細資訊,請參閱驗證使用者輸入

下列程式碼範例顯示如何利用參數傳遞值。參數的大小是定義成 5 個字元,因此將參數加入命令時,如果在 TextBox 控制項中送出較長的字串值,則會擲回例外狀況。然而,即使大小已足以容納惡意的 Transact-SQL 片段,也只會將片段視為值的部分,而非可執行的 Transact-SQL 程式碼。在這個範例中,為了維持簡潔的程式碼,我們省略了例外處理。如需詳細資訊,請參閱本主題稍後的Exception Handling and Logging

' Retrieve CustomerID to search for.
Dim ID As String = TextBox1.Text

Dim query As String = _
    "SELECT * FROM Orders WHERE CustomerID = @CustomerID"

Dim cmd As SqlCommand = New SqlCommand(query, conn)
cmd.Parameters.Add("@CustomerID", SqlDbType.VarChar, 5).Value = ID

' Code connecting to a data source has been omitted for brevity.
Dim reader As SqlDataReader = cmd.ExecuteReader()
' Process results.
reader.Close()
// Retrieve CustomerID to search for.
string ID = TextBox1.Text;

string queryString = "SELECT * FROM Orders WHERE CustomerID = @CustomerID";

SqlCommand cmd = new SqlCommand(queryString, conn);
cmd.Parameters.Add("@CustomerID", SqlDbType.VarChar, 5).Value = ID;

// Code connecting to a data source has been omitted for brevity.
SqlDataReader reader = cmd.ExecuteReader();
' Process results.
reader.Close();

例外處理和記錄

攻擊者通常利用例外狀況的資訊,例如伺服器、資料庫或資料表名稱,來對系統設置攻擊。由於例外狀況可能包含有關應用程式或資料來源的特定資訊,所以您可以只將必要的資訊公開給用戶端,使應用程式和資料來源有更嚴密的保護。如需詳細資訊,請參閱例外處理基礎觀念處理例外狀況的最佳作法。如需 ASP.NET 應用程式之例外處理的詳細資訊,請參閱 HOW TO:顯示安全錯誤訊息。如需記錄錯誤的詳細資訊,請參閱 HOW TO:寫入應用程式事件記錄檔 (Visual C#)HOW TO:寫入應用程式事件記錄檔

請參閱

其他資源

保護 ADO.NET 應用程式的安全
安全程式碼撰寫方針