person encoding in laptop

防範SQL注入攻擊的實用方法

隨著網絡安全日益受到重視,防範SQL注入攻擊成為了許多開發者的重要課題。本文將向您介紹四種防範SQL注入攻擊的主要方法。

  • Use of Prepared Statements

Use of Prepared Statements (with Parameterized Queries) 使用帶參數化查詢的Prepared Statements是防範SQL注入攻擊的首要方法。
這種方法要求開發者先定義所有的SQL代碼,然後再將每個參數傳遞給查詢。
這樣,無論用戶輸入的內容如何,數據庫都能夠區分代碼和數據。

// 這裡應該對 custname 進行驗證
String custname = request.getParameter("customerName");
// 執行輸入驗證以檢測攻擊
String query = "SELECT account_balance FROM user_data WHERE user_name = ? ";
PreparedStatement pstmt = connection.prepareStatement( query );
pstmt.setString( 1, custname);
ResultSet results = pstmt.executeQuery( );

在這個範例中,開發者使用帶參數化查詢的 PreparedStatement 來執行查詢。首先,開發者定義了 SQL 查詢,其中包含一個佔位符(用 ‘?’ 表示)。然後,開發者使用 setString 方法將 custname 變量的值綁定到佔位符。最後,執行查詢並獲取結果。

這種方法確保攻擊者無法更改查詢的目的,即使攻擊者插入了 SQL 命令。帶參數化查詢將用戶輸入視為數據,而不是 SQL 代碼的一部分,從而提高了應用程序的安全性。

  • Use of Properly Constructed Stored Procedures

Use of Properly Constructed Stored Procedures 適當構建的Stored Procedures也可以防範SQL注入攻擊。
開發者可以將查詢邏輯嵌入到存儲過程中,然後通過傳遞參數來執行查詢。
這樣,即使用戶輸入包含惡意SQL代碼,也無法影響查詢的邏輯。

// 這裡應該對 customerName 進行驗證
String customerName = request.getParameter("customerName");
// 執行輸入驗證以檢測攻擊
String storedProcedure = "{call sp_getAccountBalance(?)}";
CallableStatement callableStatement = connection.prepareCall(storedProcedure);
callableStatement.setString(1, customerName);
ResultSet results = callableStatement.executeQuery();

在這個範例中,開發者使用 Java 的 CallableStatement 來執行預先定義在數據庫中的存儲過程 sp_getAccountBalance。首先,開發者創建一個 CallableStatement 對象,其中包含要調用的存儲過程的名稱和佔位符(用 ‘?’ 表示)。然後,使用 setString 方法將 customerName 變量的值綁定到佔位符。最後,執行存儲過程並獲取結果。

使用適當構建的存儲過程有助於將用戶輸入視為數據,而不是 SQL 代碼的一部分,從而提高應用程序的安全性。

  • Allow-list Input Validation

Allow-list Input Validation 允許列表輸入驗證是一種對用戶輸入進行嚴格驗證的方法。
開發者可以將允許的值列入一個列表,然後在執行查詢之前檢查用戶輸入是否包含在該列表中。
只有經過驗證的輸入才能被用於查詢。

// 取得用戶輸入的表名
String userInputTableName = request.getParameter("tableName");

// 允許的表名清單
List<String> allowedTableNames = Arrays.asList("table1", "table2", "table3");

// 驗證用戶輸入的表名是否在允許的表名清單中
if (allowedTableNames.contains(userInputTableName)) {
    // 輸入驗證通過,執行後續操作,例如執行查詢
    String query = "SELECT * FROM " + userInputTableName;
} else {
    // 輸入驗證未通過,拒絕請求或返回錯誤信息
    throw new IllegalArgumentException("Invalid table name provided.");
}

在這個範例中,開發者通過檢查用戶輸入的表名是否在允許的表名清單中來進行 Allow-list Input Validation。如果用戶輸入的表名在允許的表名清單中,則允許執行後續操作(例如執行查詢)。否則,拒絕請求或返回錯誤信息。

這種方法有助於確保僅接受預期的輸入,從而提高應用程序的安全性。

  • Escaping All User Supplied Input

Escaping All User Supplied Input 對所有用戶提供的輸入進行轉義是另一種防範SQL注入攻擊的方法。
開發者可以根據所使用的數據庫選擇相應的轉義方案,以確保用戶輸入不會與開發者編寫的SQL代碼混淆。
然而,這種方法相對其他防禦手段較為脆弱,只有在無法實施其他方法時才應作為最後的選擇。

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import org.owasp.esapi.ESAPI;
import org.owasp.esapi.codecs.MySQLCodec;
import org.owasp.esapi.codecs.Codec;

public class EscapingExample {

    public ResultSet getResults(Connection connection, String userInput) throws Exception {
        Codec mysqlCodec = new MySQLCodec(MySQLCodec.Mode.ANSI);

        // 對用戶輸入進行轉義
        String escapedUserInput = ESAPI.encoder().encodeForSQL(mysqlCodec, userInput);

        // 創建查詢
        String query = "SELECT * FROM users WHERE username = '" + escapedUserInput + "'";

        // 執行查詢
        Statement statement = connection.createStatement();
        ResultSet resultSet = statement.executeQuery(query);

        return resultSet;
    }
}

在這個範例中,開發者使用 OWASP 的 ESAPI 函式庫對用戶輸入進行轉義。首先,使用 MySQLCodec 來對用戶輸入進行轉義,然後將轉義後的輸入用於構建查詢。這種方法可以防止用戶輸入被解釋為 SQL 代碼,從而提高應用程序的安全性。

請注意,這種方法應該作為最後手段使用,當其他方法(如使用 Prepared Statements、Stored Procedures 或 Allow-list Input Validation)不可行時。

除了以上四種主要方法外,開發人員還可以通過實施最小權限原則和作為次要防禦的允許列表輸入驗證來進一步提高應用程序的安全性。

最小權限原則要求應用程序只能訪問執行特定任務所需的最小數據和功能,這有助於減少SQL注入攻擊的風險。

而次要防禦的允許列表輸入驗證則意味著在所有情況下都對用戶輸入進行驗證,即使在使用綁定變量的情況下。

總之,防範SQL注入攻擊的方法有很多,開發者可以根據自己的需求和應用程序的特點選擇最合適的方法。

通過使用Prepared Statements(帶參數化查詢)、適當構建的Stored Procedures、允許列表輸入驗證以及對所有用戶提供的輸入進行轉義等方法,開發人員可以有效地保護應用程序免受SQL注入攻擊的侵害。

Similar Posts

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *