2009-06-19 157 views
14

是否有與PHP的mysql_real_escape_string()等價的Java?PHP的mysql等價物mysql_real_escape_string()

這是爲了在將它們傳遞給Statement.execute()之前轉義SQL注入嘗試。

我知道我可以使用PreparedStatement來代替,但我們假設這些是一次性語句,所以準備它們將導致lower performance。我已經將代碼改爲使用PreparedStatement,但考慮到現有代碼的結構,escape()函數會使代碼更改變得更簡單,以便於檢查和維護;我更喜歡容易維護代碼,除非有額外複雜性的令人信服的理由。 PreparedStatements也由數據庫以不同方式處理,因此這可能會使我們發現我們以前沒有遇到過的數據庫中的錯誤,在發佈到生產之前需要進行更多測試。

Apache StringEscapeUtils escapeSQL()只能轉義單引號。

後記: 我繼承的環境中有許多微妙之處,我故意避免在我的問題中。

兩點考慮:

1)預處理語句是不是萬能的,不提供對SQL注入100%的保護。一些數據庫驅動程序使用不安全的字符串連接實例化參數化查詢,而不是將查詢預編譯爲二進制形式。另外,如果你的SQL依賴於存儲過程,你需要確保存儲過程本身不會以不安全的方式構建查詢。

2)最準備好的語句實現將語句綁定到語句實例化的數據庫連接上。如果您正在使用數據庫連接池,則需要注意
僅使用準備好的語句引用與其準備的連接。一些池化機制確實透明地實現了這一點。否則,您可以彙總準備好的語句,或者(最簡單但更多的開銷)爲每個查詢創建一個新的準備好的語句。

+0

您喜歡易維護的代碼,但你寧願使用手動串逃逸,而不是PrearedStatement? – skaffman 2009-06-19 15:11:46

+1

考慮到現有的代碼(我沒有寫),是的,它會更容易維護。 – 2009-06-19 15:16:57

+1

較低的性能可能比安全風險更具吸引力。安全處罰可能太高。在應用程序初始化代碼中準備你的語句,並且懲罰可能是不明顯的(當然,取決於應用程序)。 – Cheekysoft 2009-06-22 16:33:56

回答

12

據我所知,沒有「標準」的方式來做到這一點。

我強烈建議儘管您目前的擔憂使用準備好的語句。性能影響可以忽略不計 - 我們也有類似的情況,每秒幾千條語句 - 其中大多數也是一次性的。

您獲得的安全性應該高於您尚未見過的性能問題。在我看來,這是「不要過早優化」的明確情況。

在任何情況下,如果您以後發現遇到性能問題,確保準備好的語句真的是通過分析仔細分析然後尋找替代品的原因。直到那時你應該避免試圖逃避權利的麻煩。

這更重要,因爲我推斷你正在開發某種面向公衆的網站 - 內部應用很少有足夠的流量來關心性能。

+1

謝謝你回答我問的問題! – 2009-06-19 15:17:41

5

不要認爲PreparedStatements比較慢。嘗試一下,衡量一下,然後再判斷。

的PreparedStatement應該始終優先於聲明來使用,幾乎無一例外,尤其當SQL注入攻擊是你要躲避什麼。

3

避免SQL注入的唯一合理方法是使用準備/參數化語句。

例如PreparedStatement您試圖避免出於某種原因。如果你做一次性陳述,準備時間應該可以忽略不計(「一次性」和「性能至關重要」是矛盾的,恕我直言)。如果你在循環中做事情,準備好的語句甚至會導致性能增加。

6

這是一些代碼,它可以實現你正在尋找的東西。最初在Vnet Publishing維基上。

https://web.archive.org/web/20131202082741/http://wiki.vnetpublishing.com/Java_Mysql_Real_Escape_String

/** 
    * Mysql Utilities 
    *   
    * @author Ralph Ritoch <[email protected]> 
    * @copyright Ralph Ritoch 2011 ALL RIGHTS RESERVED 
    * @link http://www.vnetpublishing.com 
    * 
    */ 

package vnet.java.util; 

public class MySQLUtils { 

    /** 
     * Escape string to protected against SQL Injection 
     * 
     * You must add a single quote ' around the result of this function for data, 
     * or a backtick ` around table and row identifiers. 
     * If this function returns null than the result should be changed 
     * to "NULL" without any quote or backtick. 
     * 
     * @param link 
     * @param str 
     * @return 
     * @throws Exception 
     */ 

    public static String mysql_real_escape_string(java.sql.Connection link, String str) 
      throws Exception 
    { 
     if (str == null) { 
      return null; 
     } 

     if (str.replaceAll("[[email protected]#$%^&*()-=+~.;:,\\Q[\\E\\Q]\\E<>{}\\/? ]","").length() < 1) { 
      return str; 
     } 

     String clean_string = str; 
     clean_string = clean_string.replaceAll("\\\\", "\\\\\\\\"); 
     clean_string = clean_string.replaceAll("\\n","\\\\n"); 
     clean_string = clean_string.replaceAll("\\r", "\\\\r"); 
     clean_string = clean_string.replaceAll("\\t", "\\\\t"); 
     clean_string = clean_string.replaceAll("\\00", "\\\\0"); 
     clean_string = clean_string.replaceAll("'", "\\\\'"); 
     clean_string = clean_string.replaceAll("\\\"", "\\\\\""); 

     if (clean_string.replaceAll("[[email protected]#$%^&*()-=+~.;:,\\Q[\\E\\Q]\\E<>{}\\/?\\\\\"' ]" 
      ,"").length() < 1) 
     { 
      return clean_string; 
     } 

     java.sql.Statement stmt = link.createStatement(); 
     String qry = "SELECT QUOTE('"+clean_string+"')"; 

     stmt.executeQuery(qry); 
     java.sql.ResultSet resultSet = stmt.getResultSet(); 
     resultSet.first(); 
     String r = resultSet.getString(1); 
     return r.substring(1,r.length() - 1);  
    } 

    /** 
     * Escape data to protected against SQL Injection 
     * 
     * @param link 
     * @param str 
     * @return 
     * @throws Exception 
     */ 

    public static String quote(java.sql.Connection link, String str) 
      throws Exception 
    { 
     if (str == null) { 
      return "NULL"; 
     } 
     return "'"+mysql_real_escape_string(link,str)+"'"; 
    } 

    /** 
     * Escape identifier to protected against SQL Injection 
     * 
     * @param link 
     * @param str 
     * @return 
     * @throws Exception 
     */ 

    public static String nameQuote(java.sql.Connection link, String str) 
      throws Exception 
    { 
     if (str == null) { 
      return "NULL"; 
     } 
     return "`"+mysql_real_escape_string(link,str)+"`"; 
    } 

} 
2

org.apache.commons.lang.StringEscapeUtils.class在公地lang.jar能夠解決您的問題!

0

根據Daniel Schneller的說法,在Java中沒有標準的方法來處理PHP的mysql_real_escape_string() 我所做的就是鏈接replaceAll方法來處理可能需要避免任何異常的每個方面。下面是我的示例代碼:

public void saveExtractedText(String group,String content) { try { content = content.replaceAll("\\", "\\\\") .replaceAll("\n","\\n") .replaceAll("\r", "\\r") .replaceAll("\t", "\\t") .replaceAll("\00", "\\0") .replaceAll("'", "\\'") .replaceAll("\\"", "\\\"");

 state.execute("insert into extractiontext(extractedtext,extractedgroup) values('"+content+"','"+group+"')"); 
    } catch (Exception e) { 
     e.printStackTrace(); 

    }