防sql注入 盲注等措施 ESAPI的使用


SQL注入往往是在程序員編寫包含用戶輸入的動態數據庫查詢時產生的,但其實防范SQL注入的方法非常簡單。程序員只要a)不再寫動態查詢,或b)防止用戶輸入包含能夠破壞查詢邏輯的惡意SQL語句,就能夠防范SQL注入。在這篇文章中,我們將會說明一些非常簡單的防止SQL注入的方法。

我們用以下Java代碼作為示例,

String query =SELECT account_balance FROM user_data WHERE user_name =

  + request.getParameter(customerName);

 

try {

Statement statement  = connection.createStatement( …);

ResultSet results = Statement.executeQuery(query);

}

在以上代碼中,我們可以看到並未對變量customerName做驗證,customerName的值可以直接附在query語句的后面傳送到數據庫執行,則攻擊者可以將任意的sql語句注入。

防范方法1:參數化查詢

參數化查詢是所有開發人員在做數據庫查詢時首先需要學習的,參數化查詢迫使所有開發者首先要定義好所有的SQL代碼,然后再將每個參數逐個傳入,這種編碼風格就能夠讓數據庫辨明代碼和數據。

參數化查詢能夠確保攻擊者無法改變查詢的內容,在下面修正過的例子中,如果攻擊者輸入了UsrID是“’or ‘1 ‘=’1”,參數化查詢會去查找一個完全滿足名字為‘or ‘1 ‘=’ 1的用戶。

對於不同編程語言,有一些不同的建議:

Java EE——使用帶綁定變量的PreparedStatement()

.Net——使用帶綁定變量的諸如SqlCommand()OleDbCommand()的參數化查詢;

PHP——使用帶強類型的參數化查詢PDO(使用bindParam());

Hibernate——使用帶綁定變量的createQuery()

Java示例:

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();

      

C# .Net示例:

String query =SELECT account_balance FROM user_data WHERE user_name = ?;

Try {     

OleDbCommand command = new OleDbCommand(query,connection);

command.Parameters.Add(new OleDbParameter(customerName,CustomerName.Text));

OleDbDataReader reader = command.ExecuteReader();

}catch (OleDbException se){

//error handling

}

 

防范方法二:存儲過程

存儲過程和參數化查詢的作用是一樣的,唯一的不同在於存儲過程是預先定義並存放在數據庫中,從而被應用程序調用的。

Java存儲過程示例:

      String custname = request.getParameter(customerName);

      try {

CallableStatement cs = connection.prepareCall(call sp_getAccountBalance(?)});

cs.setString(1,custname);

Result results = cs.executeQuery();

      }catch(SQLException se){

             //error handling

      }

 

VB .Net存儲過程示例:

Try

Dim command As SqlCommand = new SqlCommand(sp_getAccountBalance,connection)

 command.CommandType = CommandType.StoredProcedure

 command.Parameters.Add(new SqlParameter(@CustomerName,CustomerName.Text))

 Dim reader As SqlDataReader = command.ExecuteReader()

 ‘…

Catch se As SqlException

 ‘error handling

End Try

 

防范方法三:對所有用戶輸入進行轉義

我們知道每個DBMS都有一個字符轉義機制來告知DBMS輸入的是數據而不是代碼,如果我們將所有用戶的輸入都進行轉義,那么DBMS就不會混淆數據和代碼,也就不會出現SQL注入了。

當然,如果要采用這種方法,那么你就需要對所使用的數據庫轉義機制,也可以使用現存的諸如OWASP ESAPIescaping routinesESAPI目前是基於MySQLOracle的轉義機制的,使用起來也很方便。一個OracleESAPI的使用示例如下:

ESAPI.encoder().encodeForSQL(new OracleCodec(),queryparam);

那么,假設你有一個要訪問Oracle數據庫的動態查詢代碼如下:

String query =SELECT user_id FROM user_data WHERE user_name = ‘+req.getParameter(userID)+’ and user_password = ‘+req.getParameter(pwd)+;

try {

      Statement statement = connection.createStatement(…);

      ResultSet results = statement.executeQuery(query) ;

}

那么,你就必須重寫你的動態查詢的第一行如下:

Codec ORACLE_CODEC = new OracleCodec();

String query =SELECT user_id FROM user_data WHERE user_name = ‘+

ESAPI.encoder().encodeForSQL(ORACLE_CODEC,req.getParameter(userID))+’ and user_password = ‘+

ESAPI.encoder().encodeForSQL(ORACLE_CODEC,req.getParameter(pwd))+;

 

當然,為了保證自己代碼的可讀性,我們也可以構建自己的OracleEncoder

Encoder e = new OracleEncoder();

String query =SELECT user_id FROM user_data WHERE user_name = ‘

      + oe.encode(req.getParameter(userID)) +’ and user_password = ‘

      + oe.encode(req.getParameter(pwd))+;

 

除了上面所說的三種防范方法以外,我們還建議可以用以下兩種附加的方法來防范SQL注入:最小權限法、輸入驗證白名單法。

最小權限法:

為了避免注入攻擊對數據庫造成的損害,我們可以把每個數據庫用戶的權限盡可能縮小,不要把DBA或管理員的權限賦予你應用程序賬戶,在給用戶權限時是基於用戶需要什么樣的權限,而不是用戶不需要什么樣的權限。當一個用戶只需要讀的權限時,我們就只給他讀的權限,當用戶只需要一張表的部分數據時,我們寧願另建一個視圖讓他訪問。

如果你的策略是都是用存儲過程的話,那么僅允許應用程序的賬戶執行這些查詢,而不給他們直接訪問數據庫表的權限。諸如此類的最小權限法能夠在很大程度上保證我們數據庫的安全。

輸入驗證白名單法:

輸入驗證能夠在數據傳遞到SQL查詢前就察覺到輸入是否正確合法,采用白名單而不是黑名單則能在更大程度上保證數據的合法性。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM