2009-06-19 27 views
14

¿Existe un Java equivalente a mysql_real_escape_string() de PHP?Java equivalente para mysql_real_escape_string() de PHP

Esto es para evitar intentos de inyección de SQL antes de pasarlos a Statement.execute().

Sé que puedo usar PreparedStatement en su lugar, pero supongamos que estas son declaraciones de un solo disparo por lo que su preparación dará como resultado lower performance. Ya he cambiado el código para usar PreparedStatement, pero dada la forma en que se ha estructurado el código existente, una función de escape (escape) haría que el código sea mucho más simple de revisar y mantener; Prefiero un código fácil de mantener a menos que exista una razón convincente para la complejidad adicional. Además, la base de datos maneja de manera diferente los estados preparados, por lo que esto podría exponernos a errores en la base de datos con los que no nos hemos encontrado antes, y que requieren más pruebas antes de lanzarlos a la producción.

Apache StringEscapeUtils escapeSQL() solo escapa de comillas simples.

Postscript: Hay muchas sutilezas en el entorno que heredé que evité deliberadamente en mi pregunta.

dos puntos a considerar:

1) declaraciones preparadas no son una panacea y no ofrecen una protección del 100% contra la inyección de SQL. Algunos controladores de base de datos instancian consultas parametrizadas utilizando una concatenación de cadenas inseguras, en lugar de precompilar la consulta a una forma binaria. Además, si su SQL depende de procedimientos almacenados, debe asegurarse de que los procedimientos almacenados no generen consultas de forma insegura.

2) La implementación de la declaración más preparada vincula la declaración a la conexión de la base de datos en la que se creó la instancia de la declaración. Si está utilizando la agrupación de conexiones de bases de datos, debe tener cuidado al
utilizar la referencia de declaración preparada solo con la conexión en la que se preparó. Algunos mecanismos de puesta en común implementan esto de forma transparente. De lo contrario, podría agrupar también las declaraciones preparadas o (más simple pero más sobrecarga) crear una nueva declaración preparada para cada consulta.

+0

Prefiere fácil de mantener el código, y sin embargo, prefiere utilizar la cadena manual de escape en lugar de PrearedStatement? – skaffman

+1

Dada la forma en que el código existente (que no escribí) es, sí, sería más fácil de mantener. –

+1

el menor rendimiento puede ser más atractivo que el riesgo de seguridad. la pena de seguridad puede ser demasiado alta. Prepare sus declaraciones en el código de inicialización de la aplicación y la penalización puede no ser notoria (depende de la aplicación, por supuesto). – Cheekysoft

Respuesta

12

Por lo que sé, no hay una forma "estándar" de hacerlo.

Sugiero utilizar declaraciones preparadas a pesar de sus preocupaciones actuales. El impacto en el rendimiento va a ser insignificante: tenemos una situación similar con varios miles de extractos por segundo, la mayoría de ellos también de una sola vez.

La seguridad que obtienes debe pesarse mucho más que un problema de rendimiento que aún no hayas visto.En mi opinión, esta es una situación clara de "No optimizar de forma prematura".

En cualquier caso, si en realidad descubre que tiene problemas de rendimiento, asegúrese de que las declaraciones preparadas sean realmente la causa al elaborar perfiles cuidadosamente y luego buscar alternativas. Hasta entonces deberías ahorrarte la molestia de tratar de conseguir el escape correcto.

Esto es aún más importante ya que deduzco que está desarrollando un tipo de sitio público: las aplicaciones internas rara vez reciben suficiente tráfico como para preocuparse por el rendimiento de todos modos.

+1

¡Gracias por comenzar respondiendo la pregunta que hice! –

+0

De nada :) –

5

No asuma que los estados preparados son más lentos. Pruébalo, mídelo y luego juzga.

PreparedStatements deben siempre ser utilizados con preferencia a Norma, casi sin excepción, en especial cuando los ataques de inyección SQL son lo que estamos tratando de evitar.

3

La única forma sensata de evitar la inyección de SQL es usar declaraciones preparadas/parametrizadas.

Por ejemplo, el PreparedStatement que está intentando evitar por algún motivo. Si realiza declaraciones de una sola vez, el tiempo para prepararlas debe ser insignificante ("one-shot" y "performance-critical" es una contradicción, en mi humilde opinión). Si hace las cosas en un bucle, las declaraciones preparadas incluso pueden aumentar el rendimiento.

6

Aquí hay algunos códigos que logran lo que estás buscando. Originalmente en la wiki de 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)+"`"; 
    } 

} 
+1

Esto es una locura. Ni siquiera puedo imaginarme qué hace ese código. – droope

+2

@droope el código comprueba si hay caracteres peligrosos en una cadena. Si no, la cadena se devuelve sin procesamiento. El código luego verifica si el escaparse de la cadena normalmente elimina los caracteres posiblemente peligrosos. Si es así, la cadena se devuelve en el formulario de escape. Finalmente, la cadena escapada se envía a MySQL para ser escapada por la función QUOTE, que está específicamente destinada a cadenas de escape. –

+0

el enlace ya no funciona –

2

org.apache.commons.lang.StringEscapeUtils.class en commons-lang.jar podrían resolver su problema!

+0

Esto fue lo que usé. – droope

0

De acuerdo con Daniel Schneller, no existe una forma estándar para manejar mysql_real_escape_string() de PHP en Java Lo que hice fue encadenar todo el método de reemplazo para manejar todos los aspectos que pudieran ser necesarios para evitar cualquier excepción. Aquí está mi código de ejemplo:

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

    } 

Cuestiones relacionadas