Pregunta

Estoy intentando implementar alguna inyección anti sql en Java y me resulta muy difícil trabajar con la función de cadena "replaceAll".En última instancia, necesito una función que convierta cualquier existente \ a \\, cualquier " a \", cualquier ' a \', y cualquier \n a \\n de modo que cuando la cadena sea evaluada por MySQL, las inyecciones SQL se bloquearán.

Ingresé un código con el que estaba trabajando y todos los \\\\\\\\\\\ en la función están haciendo que mis ojos se vuelvan locos.Si alguien tiene un ejemplo de esto se lo agradecería mucho.

¿Fue útil?

Solución

PreparedStatements es el camino a seguir, porque hacen imposible la inyección de SQL. Aquí hay un ejemplo simple que toma la entrada del usuario como parámetros:

public insertUser(String name, String email) {
   Connection conn = null;
   PreparedStatement stmt = null;
   try {
      conn = setupTheDatabaseConnectionSomehow();
      stmt = conn.prepareStatement("INSERT INTO person (name, email) values (?, ?)");
      stmt.setString(1, name);
      stmt.setString(2, email);
      stmt.executeUpdate();
   }
   finally {
      try {
         if (stmt != null) { stmt.close(); }
      }
      catch (Exception e) {
         // log this error
      }
      try {
         if (conn != null) { conn.close(); }
      }
      catch (Exception e) {
         // log this error
      }
   }
}

No importa qué caracteres estén en el nombre y el correo electrónico, esos caracteres se colocarán directamente en la base de datos. No afectarán la declaración INSERT de ninguna manera.

Existen diferentes métodos establecidos para diferentes tipos de datos: el que use dependerá de los campos de su base de datos. Por ejemplo, si tiene una columna INTEGER en la base de datos, debe usar un método setInt. La documentación de PreparedStatement enumera todos los diferentes métodos disponibles para configurar y obtener datos.

Otros consejos

La única forma de evitar la inyección de SQL es con SQL parametrizado. Simplemente no es posible crear un filtro que sea más inteligente que las personas que piratean SQL para ganarse la vida.

Por lo tanto, utilice los parámetros para todas las entradas, actualizaciones y cláusulas where. Dynamic SQL es simplemente una puerta abierta para los piratas informáticos, y eso incluye SQL dinámico en los procedimientos almacenados. Parametrizar, parametrizar, parametrizar.

Si realmente no puede usar Defensa Opción 1: Declaraciones preparadas (consultas parametrizadas) o Defensa Opción 2: Procedimientos almacenados , no cree su propia herramienta, use el OWASP Enterprise Security API . Del OWASP ESAPI alojado en Google Code:

  

Don & # 8217; t escriba sus propios controles de seguridad! Reinventar la rueda cuando se trata de desarrollar controles de seguridad para cada aplicación web o servicio web genera tiempo perdido y agujeros de seguridad masivos. Los OWASP Enterprise Security API (ESAPI) Toolkits ayudan a los desarrolladores de software a protegerse contra la seguridad & # 8208; fallas de diseño e implementación relacionadas.

Para obtener más detalles, consulte Prevención de la inyección de SQL en Java y Hoja de trucos de prevención de inyección SQL .

Preste especial atención a Opción de defensa 3: escapando a todos los usuarios. a> que presenta el proyecto OWASP ESAPI ).

(Esto es en respuesta al comentario del OP bajo la pregunta original; estoy completamente de acuerdo en que PreparedStatement es la herramienta para este trabajo, no expresiones regulares).

Cuando dice \n, ¿quiere decir la secuencia \ + n o un carácter de salto de línea real? Si es <=> + <=>, la tarea es bastante sencilla:

s = s.replaceAll("['\"\\\\]", "\\\\$0");

Para hacer coincidir una barra diagonal inversa en la entrada, colocas cuatro de ellas en la cadena de expresiones regulares. Para poner una barra diagonal inversa en la salida, coloque cuatro de ellas en la cadena de reemplazo. Esto supone que está creando expresiones regulares y reemplazos en forma de literales de cadenas de Java. Si los crea de otra manera (por ejemplo, al leerlos desde un archivo), no tiene que hacer todo ese doble escape.

Si tiene un carácter de salto de línea en la entrada y desea reemplazarlo con una secuencia de escape, puede hacer un segundo pase sobre la entrada con esto:

s = s.replaceAll("\n", "\\\\n");

O tal vez desee dos barras invertidas (no lo tengo muy claro):

s = s.replaceAll("\n", "\\\\\\\\n");

Las declaraciones preparadas son el camino a seguir en la mayoría, pero no en todos los casos. A veces se encontrará en una situación en la que una consulta, o una parte de ella, debe construirse y almacenarse como una cadena para su uso posterior. Consulte la Hoja de trucos de prevención de inyecciones SQL en la Sitio OWASP para más detalles y API en diferentes lenguajes de programación.

El uso de una expresión regular para eliminar texto que podría causar una inyección SQL suena como si la instrucción SQL se enviara a la base de datos a través de un Statement en lugar de PreparedStatement .

Una de las formas más fáciles de evitar una inyección SQL en primer lugar es usar un <=>, que acepta datos para sustituir en una declaración SQL utilizando marcadores de posición, que no se basa en concatenaciones de cadenas para crear una declaración SQL para enviar a la base de datos.

Para obtener más información, Uso de declaraciones preparadas de Los Tutoriales de Java serían un buen lugar para comenzar.

Las declaraciones preparadas son la mejor solución, pero si realmente necesita hacerlo manualmente, también puede usar StringEscapeUtils clase de la biblioteca Apache Commons-Lang. Tiene un escapeSql(String) método, que puede usar:

import org.apache.commons.lang.StringEscapeUtils; … String escapedSQL = StringEscapeUtils.escapeSql(unescapedSQL);

En caso de que esté lidiando con un sistema heredado, o si tiene demasiados lugares para cambiar a PreparedStatement s en muy poco tiempo, es decir, si hay un obstáculo para usar la mejor práctica sugerida por otras respuestas, puede intentar AntiSQLFilter

Necesita el siguiente código a continuación. De un vistazo, esto puede parecerse a cualquier código antiguo que inventé. Sin embargo, lo que hice fue mirar el código fuente de http://grepcode.com/file/repo1.maven.org/maven2/mysql/mysql-connector-java/5.1.31/com/mysql/jdbc/PreparedStatement .java . Luego, después de eso, busqué cuidadosamente el código de setString (int parameterIndex, String x) para encontrar los caracteres que escapan y lo personalicé a mi propia clase para que pueda usarse para los fines que usted necesita. Después de todo, si esta es la lista de personajes de los que Oracle escapa, entonces saber esto es realmente reconfortante en cuanto a seguridad. Tal vez Oracle necesite un empujón para agregar un método similar a este para la próxima versión principal de Java.

public class SQLInjectionEscaper {

    public static String escapeString(String x, boolean escapeDoubleQuotes) {
        StringBuilder sBuilder = new StringBuilder(x.length() * 11/10);

        int stringLength = x.length();

        for (int i = 0; i < stringLength; ++i) {
            char c = x.charAt(i);

            switch (c) {
            case 0: /* Must be escaped for 'mysql' */
                sBuilder.append('\\');
                sBuilder.append('0');

                break;

            case '\n': /* Must be escaped for logs */
                sBuilder.append('\\');
                sBuilder.append('n');

                break;

            case '\r':
                sBuilder.append('\\');
                sBuilder.append('r');

                break;

            case '\\':
                sBuilder.append('\\');
                sBuilder.append('\\');

                break;

            case '\'':
                sBuilder.append('\\');
                sBuilder.append('\'');

                break;

            case '"': /* Better safe than sorry */
                if (escapeDoubleQuotes) {
                    sBuilder.append('\\');
                }

                sBuilder.append('"');

                break;

            case '\032': /* This gives problems on Win32 */
                sBuilder.append('\\');
                sBuilder.append('Z');

                break;

            case '\u00a5':
            case '\u20a9':
                // escape characters interpreted as backslash by mysql
                // fall through

            default:
                sBuilder.append(c);
            }
        }

        return sBuilder.toString();
    }
}

Después de buscar una gran cantidad de solución de prueba para evitar que sqlmap se inyecte en sqlmap, en el caso de un sistema heredado que no puede aplicar declaraciones preparadas en todas partes.

java-security-cross- site-scripting-xss-and-sql-injection topic ERA LA SOLUCIÓN

probé la solución de @Richard pero no funcionó en mi caso. utilicé un filtro

  

El objetivo de este filtro es envolver la solicitud en un código propio   contenedor MyHttpRequestWrapper que transforma:

     

los parámetros HTTP con caracteres especiales (< ;, > ;, & # 8216 ;, & # 8230;) en HTML   códigos a través de org.springframework.web.util.HtmlUtils.htmlEscape (& # 8230;)   método. Nota: Hay una situación similar en Apache Commons:   org.apache.commons.lang.StringEscapeUtils.escapeHtml (& # 8230;) el SQL   caracteres de inyección (& # 8216 ;, & # 8220 ;, & # 8230;) a través de la clase Apache Commons   org.apache.commons.lang.StringEscapeUtils.escapeSql (& # 8230;)

<filter>
<filter-name>RequestWrappingFilter</filter-name>
<filter-class>com.huo.filter.RequestWrappingFilter</filter-class>
</filter>

<filter-mapping>
<filter-name>RequestWrappingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>




package com.huo.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletReponse;
import javax.servlet.http.HttpServletRequest;

public class RequestWrappingFilter implements Filter{

    public void doFilter(ServletRequest req, ServletReponse res, FilterChain chain) throws IOException, ServletException{
        chain.doFilter(new MyHttpRequestWrapper(req), res);
    }

    public void init(FilterConfig config) throws ServletException{
    }

    public void destroy() throws ServletException{
    }
}




package com.huo.filter;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

import org.apache.commons.lang.StringEscapeUtils;

public class MyHttpRequestWrapper extends HttpServletRequestWrapper{
    private Map<String, String[]> escapedParametersValuesMap = new HashMap<String, String[]>();

    public MyHttpRequestWrapper(HttpServletRequest req){
        super(req);
    }

    @Override
    public String getParameter(String name){
        String[] escapedParameterValues = escapedParametersValuesMap.get(name);
        String escapedParameterValue = null; 
        if(escapedParameterValues!=null){
            escapedParameterValue = escapedParameterValues[0];
        }else{
            String parameterValue = super.getParameter(name);

            // HTML transformation characters
            escapedParameterValue = org.springframework.web.util.HtmlUtils.htmlEscape(parameterValue);

            // SQL injection characters
            escapedParameterValue = StringEscapeUtils.escapeSql(escapedParameterValue);

            escapedParametersValuesMap.put(name, new String[]{escapedParameterValue});
        }//end-else

        return escapedParameterValue;
    }

    @Override
    public String[] getParameterValues(String name){
        String[] escapedParameterValues = escapedParametersValuesMap.get(name);
        if(escapedParameterValues==null){
            String[] parametersValues = super.getParameterValues(name);
            escapedParameterValue = new String[parametersValues.length];

            // 
            for(int i=0; i<parametersValues.length; i++){
                String parameterValue = parametersValues[i];
                String escapedParameterValue = parameterValue;

                // HTML transformation characters
                escapedParameterValue = org.springframework.web.util.HtmlUtils.htmlEscape(parameterValue);

                // SQL injection characters
                escapedParameterValue = StringEscapeUtils.escapeSql(escapedParameterValue);

                escapedParameterValues[i] = escapedParameterValue;
            }//end-for

            escapedParametersValuesMap.put(name, escapedParameterValues);
        }//end-else

        return escapedParameterValues;
    }
}

De: [Fuente]

public String MysqlRealScapeString(String str){
  String data = null;
  if (str != null && str.length() > 0) {
    str = str.replace("\\", "\\\\");
    str = str.replace("'", "\\'");
    str = str.replace("\0", "\\0");
    str = str.replace("\n", "\\n");
    str = str.replace("\r", "\\r");
    str = str.replace("\"", "\\\"");
    str = str.replace("\\x1a", "\\Z");
    data = str;
  }
return data;

}

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top