Java-escape string, aby zapobiec SQL injection

Próbuję wprowadzić trochę anty SQL injection w Javie i bardzo trudno mi pracować z funkcją" replaceAll " string. Ostatecznie potrzebuję funkcji, która przekonwertuje dowolne istniejące \ na \\, dowolne " na \", dowolne ' na \' i dowolne \n na \\n tak, że gdy łańcuch jest oceniany przez MySQL SQL Injection zostanie zablokowany.

Podkręciłem trochę kodu, z którym pracowałem i wszystkie \\\\\\\\\\\ w funkcji sprawiają, że moje oczy wariują. Jeśli ktoś tak się składa, że mam na to przykład, byłbym bardzo wdzięczny.

Author: Tim Pietzcker, 2009-11-28

11 answers

PreparedStatements są drogą do zrobienia, ponieważ sprawiają, SQL injection niemożliwe. Oto prosty przykład, w którym dane wejściowe użytkownika są parametrami:

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

Bez względu na to, jakie znaki są w nazwie i e-mailu, znaki te zostaną umieszczone bezpośrednio w bazie danych. Nie wpłyną one w żaden sposób na instrukcję INSERT.

Istnieją różne metody set dla różnych typów danych-to, którego używasz, zależy od tego, jakie są pola bazy danych. Na przykład, jeśli masz Kolumna INTEGER w bazie danych, należy użyć metody setInt. dokumentacja PreparedStatement zawiera listę wszystkich dostępnych metod ustawiania i pobierania danych.

 228
Author: Kaleb Brasee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-23 14:22:33

Jedynym sposobem, aby zapobiec SQL injection jest sparametryzowany SQL. Po prostu nie jest możliwe zbudowanie filtra, który jest mądrzejszy niż ludzie, którzy zarabiają na życie hakując SQL.

Więc użyj parametrów dla wszystkich klauzul input, updates I where. Dynamiczny SQL to po prostu otwarte drzwi dla hakerów, które obejmują dynamiczny SQL w procedurach składowanych. Parametryzować, parametryzować, parametryzować.

 45
Author: Cylon Cat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-28 16:14:16

Jeśli naprawdę nie możesz użyć Defense Option 1: Prepared Statements (Parameterized Queries) lub Defense Option 2: Stored Procedures, nie buduj własnego narzędzia, użyj OWASP Enterprise Security API. Z OWASP ESAPI hostowanego na Google Code:

Nie pisz własnych zabezpieczeń! Nowe podejście do tworzenia mechanizmów kontroli bezpieczeństwa dla każdej aplikacji internetowej lub usługi internetowej prowadzi do marnowania czasu i ogromnego bezpieczeństwa dziury. Zestawy narzędzi OWASP Enterprise Security API (ESAPI) pomagają programistom chronić się przed wadami projektowymi i wdrożeniowymi związanymi z bezpieczeństwem.

Aby uzyskać więcej informacji, zobacz Preventing SQL Injection in Java oraz Ściągawka Prevention SQL Injection.

Zwróć szczególną uwagę na opcja obrony 3: Wyjście z wszystkich danych wejściowych dostarczonych przez użytkownika , które wprowadza projekt OWASP ESAPI ).

 33
Author: Pascal Thivent,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-28 16:40:40

(jest to odpowiedź na komentarz OP pod oryginalnym pytaniem; zgadzam się całkowicie, że PreparedStatement jest narzędziem do tego zadania, a nie wyrażeniami regularnymi.)

Kiedy mówisz \n, masz na myśli sekwencję \+n czy prawdziwą postać liniową? Jeśli to \+n, zadanie jest dość proste:

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

Aby dopasować jeden ukośnik wsteczny w wejściu, należy umieścić cztery z nich w ciągu regex. Aby umieścić jeden ukośnik wsteczny na wyjściu, należy umieścić cztery z nich w łańcuchu zastępczym. Zakładając, że tworzysz wyrażenia regularne i zamienniki w postaci literałów Java String. Jeśli tworzysz je w inny sposób (np. czytając je z pliku), nie musisz robić tych wszystkich podwójnych ucieczek.

Jeśli masz znak liniowy w wejściu i chcesz go zastąpić sekwencją escape, możesz wykonać drugie przejście nad wejściem za pomocą tego:

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

A może chcesz dwa ukośniki (nie jestem zbyt jasny w tej kwestii):

s = s.replaceAll("\n", "\\\\\\\\n");
 17
Author: Alan Moore,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-10 00:35:39

PreparedStatements są sposobem, aby przejść w większości, ale nie we wszystkich przypadkach. Czasami znajdziesz się w sytuacji, w której zapytanie lub jego część musi zostać zbudowane i zapisane jako ciąg znaków do późniejszego wykorzystania. Sprawdź Arkusz SQL Injection Prevention na stronie OWASP , aby uzyskać więcej szczegółów i interfejsów API w różnych językach programowania.

 13
Author: jonnieZG,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-11 15:56:59

Używanie wyrażenia regularnego do usuwania tekstu, który może spowodować wstrzyknięcie SQL brzmi tak, jakby polecenie SQL było wysyłane do bazy danych za pośrednictwem Statement zamiast PreparedStatement.

Jednym z najprostszych sposobów zapobiegania iniekcji SQL jest użycie PreparedStatement, która akceptuje dane do zastąpienia w instrukcji SQL za pomocą elementów zastępczych, które nie polegają na połączeniach łańcuchowych w celu utworzenia instrukcji SQL do wysłania do bazy danych.

Więcej informacje, używanie gotowych instrukcji z samouczków Java byłoby dobrym miejscem na początek.

 9
Author: coobird,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-28 16:14:30

Gotowe deklaracje są najlepszym rozwiązaniem, ale jeśli naprawdę potrzebujesz zrobić to ręcznie, możesz również użyć StringEscapeUtils klasa z biblioteki Apache Commons-Lang. Posiada escapeSql(String) metoda, której możesz użyć:

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

 8
Author: ToBe_HH,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-13 21:23:03

W przypadku, gdy masz do czynienia ze starszym systemem lub masz zbyt wiele miejsc, aby przełączyć się na PreparedStatement s W zbyt krótkim czasie - tzn. jeśli istnieje przeszkoda w stosowaniu najlepszych praktyk sugerowanych przez inne odpowiedzi, możesz spróbować AntiSQLFilter

 6
Author: Bozho,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-28 16:45:08

Potrzebujesz poniższego kodu. Na pierwszy rzut oka może to wyglądać jak każdy stary kod, który wymyśliłem. Jednak to, co zrobiłem, to spojrzenie na kod źródłowy dlahttp://grepcode.com/file/repo1.maven.org/maven2/mysql/mysql-connector-java/5.1.31/com/mysql/jdbc/PreparedStatement.java. następnie uważnie przejrzałem kod setString(int parameterIndex, String x), aby znaleźć znaki, których ucieka i dostosować to do mojej własnej klasy, aby mógł być używany do celów tego potrzebujesz. Wszakĺľe jeĹ "li jest to lista postaci, ktĂłrych Oracle ucieka, wiedzÄ ... c o tym jest to naprawdÄ ™ pocieszające pod wzglÄ ™ dem bezpieczeĹ" stwa. Być może Oracle potrzebuje impulsu, aby dodać metodę podobną do tej W następnym dużym wydaniu Javy.

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();
    }
}
 6
Author: Richard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-07 08:12:58

Po przeszukiwaniu testowego rozwiązania dla zapobiegania sqlmap z SQL injection, w przypadku starszego systemu, który nie może zastosować przygotowanych stanów w każdym miejscu.

Java-security-cross-Site-scripting-xss-and-sql-injection topic BYŁO ROZWIĄZANIEM

Próbowałem @Richard s rozwiązanie, ale nie działa w moim przypadku. użyłem filtra

Celem tego filtra jest owinięcie żądania do kodu własnego wrapper MyHttpRequestWrapper który przekształca:

Parametry HTTP ze znakami specjalnymi ( ,',...) do HTML kody przez org.springframework.www.util.HtmlUtils.htmlEscape(…) metoda. Uwaga: w Apache Commons jest podobna Klasa : org.Apacz.commons.lang.StringEscapeUtils.escapeHtml (...) SQL injection characters ( ' ,",...) via the Apache Commons classe org.Apacz.commons.lang.StringEscapeUtils.escapeSql (...)

<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;
    }
}
 0
Author: shareef,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-11 20:28:46

From: [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;

}

 0
Author: Billcountry Mwaniki,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-17 12:48:21