Java equivalent for PHP's mysql_real_escape_string()

后端 未结 7 665
温柔的废话
温柔的废话 2021-01-11 10:17

Is there a Java equivalent to PHP\'s mysql_real_escape_string() ?

This is to escape SQL injection attempts before passing them to Statement.execute().

I know

相关标签:
7条回答
  • 2021-01-11 10:31

    As far as I know, there is no "standard" way to do it.

    I strongly suggest using prepared statements despite your current concerns. The performance impact is going to be negligible - we have a similar situation with several thousand statements per second - most of them one-shots as well.

    The security you gain should be weighed much higher than a performance problem you have not even seen yet. In my opinion this is a clear situation of "Don't optimize prematurely".

    In any case should you really find out later that you run into performance problems, make sure that the prepared statements are really the cause by profiling carefully and then look for alternatives. Till then you should save yourself the hassle of trying to get the escaping right.

    This is even more important as I infer you are developing some sort of public facing site - internal apps seldom get enough traffic to be concerned about performance anyway.

    0 讨论(0)
  • 2021-01-11 10:37

    According to Daniel Schneller, there is no standard way to handle PHP's mysql_real_escape_string() in Java What I did was to chain replaceAll method to handle every aspect that may be necessary to avoid any exception. Here is my sample code:

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

    0 讨论(0)
  • 2021-01-11 10:38

    I would not trust anything else than PreparedStatement to ensure security. But if you need to have a similar workflow when building queries you may use the code below. It uses a PreparedStatement underneath, works like a StringBuilder, adds escape functions and tracks the parameter indexes for you. It can be used like this:

    SQLBuilder sqlBuilder = new SQLBuilder("update ").append(dbName).append(".COFFEES ");
    sqlBuilder.append("set SALES = ").escapeString(sales);
    sqlBuilder.append(", TOTAL = ").escapeInt(total);
    sqlBuilder.append("where COF_NAME = ").escapeString(coffeeName);
    sqlBuilder.prepareStatement(connection).executeUpdate();
    

    Here's the code:

    class SQLBuilder implements Appendable {
        private StringBuilder sqlBuilder;
        private List<Object> values = new ArrayList<>();
    
        public SQLBuilder() {
            sqlBuilder = new StringBuilder();
        }
    
        public SQLBuilder(String str)
        {
            sqlBuilder = new StringBuilder(str);
        }
    
        @Override
        public SQLBuilder append(CharSequence csq)
        {
            sqlBuilder.append(csq);
            return this;
        }
    
        @Override
        public SQLBuilder append(CharSequence csq, int start, int end)
        {
            sqlBuilder.append(csq, start, end);
            return this;
        }
    
        @Override
        public SQLBuilder append(char c)
        {
            sqlBuilder.append(c);
            return this;
        }
    
        // you can add other supported parameter types here...
        public SQLBuilder escapeString(String x)
        {
            protect(x);
            return this;
        }
    
        public SQLBuilder escapeInt(int x)
        {
            protect(x);
            return this;
        }
    
        private void escape(Object o)
        {
            sqlBuilder.append('?');
            values.add(o);
        }
    
        public PreparedStatement prepareStatement(Connection connection)
            throws SQLException
        {
            PreparedStatement preparedStatement =
                connection.prepareStatement(sqlBuilder.toString());
            for (int i = 0; i < values.size(); i++)
            {
                Object value = values.get(i);
                // you can add other supported parameter types here...
                if (value instanceof String)
                    preparedStatement.setString(i + 1, (String) value);
                else if (value instanceof Integer)
                    preparedStatement.setInt(i + 1, (Integer) value);
            }
            return preparedStatement;
        }
    
        @Override
        public String toString()
        {
            return "SQLBuilder: " + sqlBuilder.toString();
        }
    }
    
    0 讨论(0)
  • 2021-01-11 10:39

    org.apache.commons.lang.StringEscapeUtils.class in commons-lang.jar could solve your problem!

    0 讨论(0)
  • 2021-01-11 10:42

    The only sensible way to avoid SQL injection is to use prepared/parameterized statements.

    For example the PreparedStatement you are trying to avoid for some reason. If you do one-shot statements, the time to prepare them should be negligible ("one-shot" and "performance-critical" is a contradiction, IMHO). If you do things in a loop, prepared statements even cause performance to increase.

    0 讨论(0)
  • 2021-01-11 10:45

    Here is some code which achieves what you are looking for. Originally on the Vnet Publishing wiki.

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

    /**
      * 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)+"`";
         }
    
     }
    
    0 讨论(0)
提交回复
热议问题