Kie*_*lly 14 java mysql sql security jdbc
是否存在类似于PHP的mysql_real_escape_string()的Java?
这是为了在将它们传递给Statement.execute()之前逃避SQL注入尝试.
我知道我可以使用PreparedStatement,但我们假设这些是一次性语句,因此准备它们会导致性能降低.我已经将代码更改为使用PreparedStatement,但考虑到现有代码的结构,escape()函数会使代码更改更容易查看和维护; 我更喜欢易于维护代码,除非有一个令人信服的理由来增加复杂性.此外,PreparedStatements由数据库以不同方式处理,因此这可能使我们暴露于数据库中我们之前未遇到过的错误,在发布到生产之前需要进行更多测试.
Apache StringEscapeUtils escapeSQL()仅转义单引号.
后记:在我继承的环境中存在许多微妙之处,我在我的问题中故意避免.
需要考虑的两点:
1)准备好的语句不是灵丹妙药,也不能提供100%的SQL注入保护.某些数据库驱动程序使用不安全的字符串连接实例化参数化查询,而不是将查询预编译为二进制形式.此外,如果您的SQL依赖于存储过程,则需要确保存储过程本身不会以不安全的方式构建查询.
2)大多数预准备语句实现将语句绑定到语句被实例化的数据库连接上.如果您正在使用数据库连接池,则需要注意
仅使用准备好的语句引用与其准备的连接.一些池化机制确实透明地实现了这一点.否则,您也可以汇集预准备语句或(最简单但更多开销)为每个查询创建一个新的预准备语句.
Dan*_*ler 12
据我所知,没有"标准"的方法来做到这一点.
尽管你目前担心,我强烈建议使用准备好的陈述.性能影响可以忽略不计 - 我们有类似的情况,每秒有几千个语句 - 其中大多数也是一次性的.
您获得的安全性应该比您尚未看到的性能问题高得多.在我看来,这是"不要过早优化"的明确情况.
在任何情况下,如果你真的发现你遇到了性能问题,请确保准备好的语句真的是通过仔细分析然后寻找替代方案的原因.直到那时你应该省去试图逃避正确的麻烦.
这更为重要,因为我推断您正在开发某种面向公众的网站 - 内部应用程序很少获得足够的流量来关注性能.
这里有一些代码可以实现您的目标.最初是在Vnet Publishing wiki上.
/**
  * Mysql Utilities
  *        
  * @author Ralph Ritoch <rritoch@gmail.com>
  * @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("[a-zA-Z0-9_!@#$%^&*()-=+~.;:,\\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("[a-zA-Z0-9_!@#$%^&*()-=+~.;:,\\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)+"`";
     }
 }
不要认为PreparedStatements较慢.试一试,测量它,然后判断.
PreparedStatements应始终优先于Statement使用,几乎毫无例外,尤其是当您正在尝试避免SQL注入攻击时.
| 归档时间: | 
 | 
| 查看次数: | 13626 次 | 
| 最近记录: |