Java – Chaîne d’échappement pour empêcher l’injection SQL

J’essaie de mettre en place une injection anti-SQL dans Java et je trouve très difficile de travailler avec la fonction de chaîne “replaceAll”. En fin de compte, j’ai besoin d’une fonction qui convertira tout \ à \\ , tout " en \" , tout \' en \' et tout \n en \\n sorte que lorsque la chaîne est évaluée par MySQL, les injections SQL seront bloquées.

J’ai branché du code avec \\\\\\\\\\\ je travaillais et tous les \\\\\\\\\\\ de la fonction font que mes yeux deviennent fous. Si quelqu’un en avait un exemple, je l’apprécierais beaucoup.

    PreparedStatements est la solution, car ils rendent l’injection SQL impossible. Voici un exemple simple prenant l’entrée de l’utilisateur comme parameters:

     public insertUser(Ssortingng name, Ssortingng email) { Connection conn = null; PreparedStatement stmt = null; try { conn = setupTheDatabaseConnectionSomehow(); stmt = conn.prepareStatement("INSERT INTO person (name, email) values (?, ?)"); stmt.setSsortingng(1, name); stmt.setSsortingng(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’email, ces caractères seront placés directement dans la firebase database. Ils n’affecteront en aucun cas l’instruction INSERT.

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

    Le seul moyen d’empêcher l’injection SQL est d’utiliser du SQL paramétré. Il n’est tout simplement pas possible de créer un filtre plus intelligent que celui qui utilise SQL pour gagner sa vie.

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

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

    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 une perte de temps et des trous de sécurité considérables. Les boîtes à outils ESAPI (OWASP Enterprise Security API) aident les développeurs de logiciels à se protéger contre les failles de conception et de mise en œuvre liées à la sécurité.

    Pour plus de détails, voir Prévention de l’injection SQL dans Java et la feuille d’arrêt de la prévention d’injection SQL .

    Portez une attention particulière à l’ option de défense n ° 3: Échapper à toutes les entrées fournies par l’utilisateur qui présente le projet OAPASP ESAPI ).

    (Ceci est en réponse au commentaire du PO sous la question initiale; je suis tout à fait d’accord avec le fait que PreparedStatement est l’outil pour ce travail, pas les regexes.)

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

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

    Pour faire correspondre une barre oblique inverse dans l’entrée, vous en mettez quatre dans la chaîne regex. Pour mettre une barre oblique inverse dans la sortie, vous en mettez 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 Ssortingng. Si vous les créez d’une autre manière (p. Ex. En les lisant à partir d’un fichier), vous n’avez pas à faire toutes ces opérations en double.

    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 vous voulez deux barres obliques inverses (je ne suis pas trop clair à ce sujet):

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

    PreparedStatements est la voie à suivre dans la plupart des cas, mais pas tous. Parfois, vous vous retrouvez dans une situation où une requête ou une partie de celle-ci doit être créée et stockée sous forme de chaîne pour une utilisation ultérieure. Consultez le Cheat Sheet de SQL Injection Prevention sur le site OWASP pour plus de détails et d’API dans différents langages de programmation.

    Utiliser une expression régulière pour supprimer du texte susceptible de provoquer une injection SQL sonne comme si l’instruction SQL était envoyée à la firebase database via une Statement plutôt que par un Statement PreparedStatement .

    L’une des manières les plus simples d’empêcher une injection SQL consiste à utiliser PreparedStatement , qui accepte les données pour les remplacer par une instruction SQL à l’aide d’espaces réservés, qui ne repose pas sur des concaténations de chaînes pour créer une instruction SQL à envoyer à la firebase database.

    Pour plus d’informations, l’ utilisation des instructions préparées à partir des didacticiels Java serait un bon sharepoint départ.

    Les instructions préparées sont la meilleure solution, mais si vous devez vraiment le faire manuellement, vous pouvez également utiliser la classe SsortingngEscapeUtils de la bibliothèque Apache Commons-Lang. Il a une escapeSql(Ssortingng) , que vous pouvez utiliser:

    import org.apache.commons.lang.SsortingngEscapeUtils; … Ssortingng escapedSQL = SsortingngEscapeUtils.escapeSql(unescapedSQL);

    Si vous avez affaire à un ancien système, ou si vous avez trop d’espaces pour passer à PreparedStatement s en trop peu de temps – c’est-à-dire qu’il existe un obstacle à l’utilisation des meilleures pratiques suggérées par d’autres réponses, vous pouvez essayer AntiSQLFilter

    Vous avez besoin du code suivant ci-dessous. D’un coup d’oeil, cela peut ressembler à n’importe quel ancien code que j’ai inventé. 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 . Ensuite, j’ai soigneusement examiné le code de setSsortingng (int parameterIndex, Ssortingng x) pour trouver les caractères qu’il échappait et les personnaliser dans ma propre classe pour pouvoir les utiliser aux fins dont vous avez besoin. Après tout, s’il s’agit de la liste de caractères qu’Oracle échappe, alors le fait de savoir cela est vraiment rassurant du sharepoint vue de la sécurité. Peut-être qu’Oracle a besoin d’un coup de pouce pour append une méthode similaire à celle-ci pour la prochaine version majeure de Java.

     public class SQLInjectionEscaper { public static Ssortingng escapeSsortingng(Ssortingng x, boolean escapeDoubleQuotes) { SsortingngBuilder sBuilder = new SsortingngBuilder(x.length() * 11/10); int ssortingngLength = 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é un grand nombre de solutions pour empêcher sqlmap de sql injection, en cas de système hérité qui ne peut pas appliquer des statuts préparés à chaque endroit.

    La rubrique java-security-cross-site-scripting-xss-et-sql-injection ÉTAIT LA SOLUTION

    J’ai essayé la solution @Richard mais je n’ai pas fonctionné dans mon cas. j’ai utilisé un filtre

    Le but de ce filtre est d’encapsuler la requête dans un wrapper MyHttpRequestWrapper à codage propre qui transforme:

    les parameters HTTP avec des caractères spéciaux (< ,>, ‘,…) dans des codes HTML via la méthode org.springframework.web.util.HtmlUtils.htmlEscape (…). Note: Il existe une classe similaire dans Apache Commons: org.apache.commons.lang.SsortingngEscapeUtils.escapeHtml (…) les caractères d’injection SQL (‘, “,…) via Apache Commons classe org.apache.commons.lang.SsortingngEscapeUtils. escapeSql (…)

      RequestWrappingFilter com.huo.filter.RequestWrappingFilter   RequestWrappingFilter /*  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.SsortingngEscapeUtils; public class MyHttpRequestWrapper extends HttpServletRequestWrapper{ private Map escapedParametersValuesMap = new HashMap(); public MyHttpRequestWrapper(HttpServletRequest req){ super(req); } @Override public Ssortingng getParameter(Ssortingng name){ Ssortingng[] escapedParameterValues = escapedParametersValuesMap.get(name); Ssortingng escapedParameterValue = null; if(escapedParameterValues!=null){ escapedParameterValue = escapedParameterValues[0]; }else{ Ssortingng parameterValue = super.getParameter(name); // HTML transformation characters escapedParameterValue = org.springframework.web.util.HtmlUtils.htmlEscape(parameterValue); // SQL injection characters escapedParameterValue = SsortingngEscapeUtils.escapeSql(escapedParameterValue); escapedParametersValuesMap.put(name, new Ssortingng[]{escapedParameterValue}); }//end-else return escapedParameterValue; } @Override public Ssortingng[] getParameterValues(Ssortingng name){ Ssortingng[] escapedParameterValues = escapedParametersValuesMap.get(name); if(escapedParameterValues==null){ Ssortingng[] parametersValues = super.getParameterValues(name); escapedParameterValue = new Ssortingng[parametersValues.length]; // for(int i=0; i 

    De: [Source]

     public Ssortingng MysqlRealScapeSsortingng(Ssortingng str){ Ssortingng 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; 

    }