Question

J'essaie de mettre en place une injection anti-SQL dans Java et je trouve très difficile de travailler avec le & "replaceAll &"; fonction de chaîne. En fin de compte, il me faut une fonction qui convertira tout \ existant en \\, tout " en \", tout ' en \', et tout \n en \\n afin que la chaîne est évalué par MySQL, les injections SQL seront bloquées.

J'ai gravé du code avec lequel je travaillais et tous les \\\\\\\\\\\ de la fonction me font mal aux yeux. Si quelqu'un en avait un exemple, je l'apprécierais grandement.

Était-ce utile?

La solution

Les déclarations préparées sont la solution, car elles rendent l’injection SQL impossible. Voici un exemple simple prenant l'entrée de l'utilisateur comme paramètre:

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
      }
   }
}

Quels que soient les caractères du nom et de l'e-mail, ces caractères seront placés directement dans la base de données. Ils n’affecteront en aucune façon l’instruction INSERT.

Il existe différentes méthodes de définition pour différents types de données. La méthode que vous utilisez dépend des champs de votre base de données. Par exemple, si vous avez une colonne INTEGER dans la base de données, vous devez utiliser une méthode setInt. La documentation de PreparedStatement répertorie toutes les différentes méthodes disponibles. pour définir et obtenir des données.

Autres conseils

La seule façon d'empêcher l'injection SQL est d'utiliser du SQL paramétré. Il est tout simplement impossible de créer un filtre plus intelligent que les personnes qui piratent SQL pour gagner sa vie.

Utilisez donc des paramètres pour toutes les clauses input, updates et where. Le SQL dynamique est simplement une porte ouverte pour les pirates, et cela inclut le SQL dynamique dans les procédures stockées. Paramétrer, paramétrer, paramétrer.

Si vous ne pouvez vraiment pas utiliser Option de défense 1: instructions préparées (requêtes paramétrées) ou Défense Option 2: Procédures stockées , ne créez pas votre propre outil, utilisez le OWASP Enterprise Security. API . OWASP ESAPI hébergé sur le code Google:

  

Don & # 8217; N'écrivez pas vos propres contrôles de sécurité! Réinventer la roue lorsqu'il s'agit de développer des contrôles de sécurité pour chaque application Web ou service Web entraîne des pertes de temps et des failles de sécurité énormes. Les boîtes à outils ESAPI (OWASP Enterprise Security API) aident les développeurs de logiciels à se prémunir contre la sécurité & # 8208; problèmes de conception et de mise en œuvre liés.

Pour plus d'informations, voir Empêcher l'injection de code SQL dans Java et Aide-mémoire de prévention de l'injection SQL .

Portez une attention particulière à la option de réconfort 3 a> qui présente le projet OWASP ESAPI ).

(Ceci est une réponse au commentaire de l'OP sous la question initiale; je suis tout à fait d'accord sur le fait que PreparedStatement est l'outil pour ce travail, pas les expressions rationnelles.)

Lorsque vous dites \n, voulez-vous dire la séquence \ + n ou un caractère de saut de ligne? Si c'est <=> + <=>, la tâche est assez simple:

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

Pour faire correspondre une barre oblique inverse dans l'entrée, vous devez en insérer quatre dans la chaîne regex. Pour insérer une barre oblique inversée dans la sortie, vous devez en insérer quatre dans la chaîne de remplacement. Cela suppose que vous créez les expressions rationnelles et les remplacements sous la forme de littéraux Java String. Si vous les créez autrement (par exemple, en les lisant dans un fichier), vous n'avez pas à faire tout ce double échappement.

Si vous avez un caractère de saut de ligne dans l'entrée et que vous souhaitez le remplacer par une séquence d'échappement, vous pouvez effectuer un second passage sur l'entrée avec ceci:

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

Ou peut-être voulez-vous deux barres obliques inverses (je ne suis pas trop clair là-dessus):

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

Les déclarations préparées sont la solution dans la plupart des cas, mais pas dans tous. Parfois, vous vous trouverez dans une situation où une requête, ou une partie de celle-ci, doit être construite et stockée sous forme de chaîne pour une utilisation ultérieure. Consultez la Aide-mémoire de prévention de l'injection SQL sur la page Site OWASP pour plus de détails et des API dans différents langages de programmation.

L'utilisation d'une expression régulière pour supprimer du texte, ce qui pourrait provoquer une injection SQL, donne l'impression que l'instruction SQL est envoyée à la base de données via un Statement plutôt qu'un PreparedStatement .

L’un des moyens les plus simples d’empêcher une injection SQL consiste à utiliser un <=>, qui accepte la substitution de données dans une instruction SQL utilisant des espaces réservés, qui ne repose pas sur des concaténations de chaînes pour créer une instruction SQL envoyer à la base de données.

Pour plus d'informations, Utilisation des instructions préparées à partir de Les tutoriels Java constituent un bon point de départ.

Les déclarations préparées sont la meilleure solution, mais si vous avez vraiment besoin de le faire manuellement, vous pouvez également utiliser StringEscapeUtils de la bibliothèque Apache Commons-Lang. Il a un escapeSql(String) , que vous pouvez utiliser:

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

Si vous utilisez un système existant, ou si vous avez trop d'endroits pour passer à PreparedStatement s en trop peu de temps - en cas d'obstacle à l'utilisation de la meilleure pratique suggérée par d'autres réponses, vous pouvez essayer AntiSQLFilter

Vous avez besoin du code suivant ci-dessous. En un coup d'œil, cela peut ressembler à n'importe quel ancien code que j'ai composé. Cependant, j’ai examiné le code source de http://grepcode.com/file/repo1.maven.org/maven2/mysql/mysql-connector-java/5.1.31/com/mysql/jdbc/PreparedStatement .java . Puis, après cela, j’ai soigneusement examiné le code de setString (int parameterIndex, String x) pour rechercher les caractères qu’il échappe et l’a personnalisé dans ma propre classe afin qu’il puisse être utilisé aux fins souhaitées. Après tout, s’il s’agit de la liste de caractères échappée par Oracle, il est alors rassurant de le faire pour la sécurité. Peut-être qu'Oracle a besoin d'un coup de pouce pour ajouter une méthode similaire à celle-ci pour la prochaine version majeure 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();
    }
}

Après avoir recherché plusieurs solutions de test pour éviter l’injection de sqlmap dans les systèmes hérités qui ne peuvent pas appliquer les instructions préparées à chaque endroit.

java-security-cross- rubrique site-scripting-xss-and-sql-injection C'ÉTAIT LA SOLUTION

J’ai essayé la solution de @Richard, mais cela n’a pas fonctionné. j'ai utilisé un filtre

  

Le but de ce filtre est d'encapsuler la demande dans un fichier propre   wrapper MyHttpRequestWrapper qui transforme:

     

les paramètres HTTP avec des caractères spéciaux (< ;, > ;, & # 8216 ;, & # 8230;) en HTML   codes via le fichier org.springframework.web.util.HtmlUtils.htmlEscape (& # 8230;)   méthode. Remarque: il existe des classes similaires dans Apache Commons:   org.apache.commons.lang.StringEscapeUtils.escapeHtml (& # 8230;) le code SQL   caractères d'injection (& # 8216 ;, & # 8220 ;, & # 8230;) via la classe 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: [Source]

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;

}

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top