ref:web 防止SQL注入方法

ref:https://blog.csdn.net/beidou321/article/details/6482618java

小結:spring採用JdbcTemplate來操做sql,通常不要自行拼接sql,而是使用參數化的構造方式,則不會存在注入問題。程序員

SQL注入每每是在程序員編寫包含用戶輸入的動態數據庫查詢時產生的,但其實防範SQL注入的方法很是簡單。程序員只要spring

a)再也不寫動態查詢b)防止用戶輸入包含可以破壞查詢邏輯的惡意SQL語句,就可以防範SQL注入。sql

在這篇文章中,咱們將會說明一些很是簡單的防止SQL注入的方法。咱們用如下Java代碼做爲示例,數據庫

String query ="SELECT account_balance FROM user_data WHERE user_name ="
  + request.getParameter("customerName");//sql語句拼接通常都有問題。除+外還有append函數也能夠搜索下。 try {
Statement statement  = connection.createStatement( …);
ResultSet results = Statement.executeQuery(query);
}

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

通常來講,sql注入有兩種:int型注入和字符串注入。對於int注入,只要在拼接時嚴格設置爲int類型,例如intval或者java中函數參數爲int,便可防止注入。api

對於字符串注入,只要對'進行轉義便可。 安全

防範方法1:參數化查詢app

參數化查詢是全部開發人員在作數據庫查詢時首先須要學習的,參數化查詢迫使全部開發者首先要定義好全部的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 = "+//注意必須有引號,若是沒有,則int類型注入就可繞過。
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查詢前就察覺到輸入是否正確合法,採用白名單而不是黑名單則能在更大程度上保證數據的合法性。

相關文章
相關標籤/搜索