Domanda

Sto cercando di mettere in atto un'iniezione anti sql in java e sto trovando molto difficile lavorare con il " sostituisci Tutti " funzione stringa. Alla fine ho bisogno di una funzione che converta qualsiasi \ esistente in \\, qualsiasi " in \", qualsiasi ' in \' e qualsiasi \n in \\n in modo che quando la stringa viene valutato da MySQL Le iniezioni di SQL verranno bloccate.

Ho preso un po 'di codice con cui stavo lavorando e tutti i \\\\\\\\\\\ nella funzione stanno facendo impazzire gli occhi. Se qualcuno dovesse avere un esempio di questo, lo apprezzerei molto.

È stato utile?

Soluzione

PreparedStatements è la strada da percorrere, perché rende impossibile l'iniezione di SQL. Ecco un semplice esempio prendendo l'input dell'utente come parametri:

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

Indipendentemente dai caratteri presenti nel nome e nell'e-mail, tali caratteri verranno inseriti direttamente nel database. Non influiranno in alcun modo sull'istruzione INSERT.

Esistono diversi metodi di impostazione per diversi tipi di dati - quale utilizzare dipende dai campi del database. Ad esempio, se nel database è presente una colonna INTEGER, è necessario utilizzare un metodo setInt. La documentazione di PreparedStatement elenca tutti i diversi metodi disponibili per impostare e ottenere dati.

Altri suggerimenti

L'unico modo per prevenire l'iniezione di SQL è con SQL parametrizzato. Semplicemente non è possibile costruire un filtro più intelligente delle persone che hackerano SQL per vivere.

Quindi usa i parametri per tutti gli input, gli aggiornamenti e le clausole where. Dynamic SQL è semplicemente una porta aperta per gli hacker e include SQL dinamico nelle procedure memorizzate. Parametrizzare, parametrizzare, parametrizzare.

Se davvero non puoi usare Opzione di difesa 1: dichiarazioni preparate (query con parametri) o Defense Opzione 2: Stored procedure , non creare il tuo strumento personale, utilizza OWASP Enterprise Security API . Da OWASP ESAPI ospitato su Google Code:

  

Don & # 8217; t scrivi i tuoi controlli di sicurezza! Reinventare la ruota quando si tratta di sviluppare controlli di sicurezza per ogni applicazione Web o servizio Web comporta perdite di tempo e enormi falle di sicurezza. Gli strumenti OWASP Enterprise Security API (ESAPI) aiutano gli sviluppatori di software a proteggersi dalla sicurezza & # 8208; relativi difetti di progettazione e implementazione.

Per maggiori dettagli, vedi Prevenzione dell'iniezione SQL in Java e Foglio informativo sulla prevenzione dell'iniezione SQL .

Presta particolare attenzione a Opzione di difesa 3: fuga da tutti gli input forniti dall'utente a> che introduce il OWASP ESAPI ).

(Questo è in risposta al commento del PO sotto la domanda originale; sono pienamente d'accordo sul fatto che PreparedStatement è lo strumento per questo lavoro, non regex.)

Quando dici \n, intendi la sequenza \ + n o un carattere di avanzamento riga effettivo? Se è <=> + <=>, l'attività è piuttosto semplice:

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

Per abbinare una barra rovesciata nell'input, ne inserisci quattro nella stringa regex. Per inserire una barra rovesciata nell'output, ne inserisci quattro nella stringa di sostituzione. Questo presuppone che tu stia creando le regex e le sostituzioni sotto forma di valori letterali String Java. Se li crei in un altro modo (ad esempio, leggendoli da un file), non devi fare tutto questo doppio escape.

Se si dispone di un carattere di avanzamento riga nell'input e si desidera sostituirlo con una sequenza di escape, è possibile effettuare un secondo passaggio sull'input con questo:

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

O forse vuoi due barre rovesciate (non sono troppo chiaro su questo):

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

PreparedStatements è la strada da percorrere nella maggior parte, ma non in tutti i casi. A volte ti troverai in una situazione in cui una query, o parte di essa, deve essere costruita e archiviata come stringa per un uso successivo. Consulta il Foglio informativo sulla prevenzione dell'iniezione SQL sul Sito OWASP per maggiori dettagli e API in diversi linguaggi di programmazione.

L'uso di un'espressione regolare per rimuovere il testo che potrebbe causare un'iniezione SQL sembra che l'istruzione SQL venga inviata al database tramite un Statement anziché PreparedStatement .

Uno dei modi più semplici per prevenire un'iniezione SQL è innanzitutto quello di utilizzare un <=>, che accetta i dati da sostituire in un'istruzione SQL usando segnaposto, che non si basa su concatenazioni di stringhe per creare un'istruzione SQL su invia al database.

Per ulteriori informazioni, Uso delle istruzioni preparate da I tutorial Java sarebbe un buon punto di partenza.

Le dichiarazioni preparate sono la soluzione migliore, ma se hai davvero bisogno di farlo manualmente puoi anche usare StringEscapeUtils dalla libreria Apache Commons-Lang. Ha un escapeSql(String) , che puoi usare:

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

Nel caso in cui tu abbia a che fare con un sistema legacy o hai troppi posti in cui passare a PreparedStatement s in un tempo troppo breve, ovvero se c'è un ostacolo all'utilizzo delle migliori pratiche suggerite da altre risposte, puoi provare AntiSQLFilter

È necessario il seguente codice di seguito. A prima vista, potrebbe sembrare un vecchio codice che ho inventato. Tuttavia, quello che ho fatto è stato guardare il codice sorgente per http://grepcode.com/file/repo1.maven.org/maven2/mysql/mysql-connector-java/5.1.31/com/mysql/jdbc/PreparedStatement .java . Quindi, ho esaminato attentamente il codice di setString (int parameterIndex, String x) per trovare i caratteri che sfugge e personalizzarlo sulla mia classe in modo che possa essere utilizzato per gli scopi di cui hai bisogno. Dopotutto, se questo è l'elenco dei personaggi a cui Oracle sfugge, sapere che questo è davvero confortante dal punto di vista della sicurezza. Forse Oracle ha bisogno di una spinta per aggiungere un metodo simile a questo per la prossima versione di 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();
    }
}

Dopo aver cercato un sacco di soluzioni per prevenire sqlmap dall'iniezione di sql, nel caso di un sistema legacy che non può applicare gli statuti preparati ovunque.

java-security-cross- argomento site-scripting-xss-e-sql-injection ERA LA SOLUZIONE

Ho provato la soluzione di @Richard ma nel mio caso non ha funzionato. ho usato un filtro

  

L'obiettivo di questo filtro è racchiudere la richiesta in un codice proprio   wrapper MyHttpRequestWrapper che trasforma:

     

i parametri HTTP con caratteri speciali (< ;, > ;, & # 8216 ;, & # 8230;) in HTML   codici tramite org.springframework.web.util.HtmlUtils.htmlEscape (& # 8230;)   metodo. Nota: esiste una classe simile in Apache Commons:   org.apache.commons.lang.StringEscapeUtils.escapeHtml (& # 8230;) SQL   caratteri di iniezione (& # 8216 ;, & # 8220 ;, & # 8230;) tramite 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;
    }
}

Da: [Fonte]

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;

}

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top