Ява - escape-последовательность для предотвращения SQL-инъекций


Я пытаюсь поставить некоторые анти sql инъекции на место в java и нахожу его очень трудно работать с функцией строки "replaceAll". В конечном счете мне нужна функция, которая преобразует любые существующие до , ни " до ", либо ' до ' и ни n до n так что, когда строка оценивается MySQL SQL инъекции будут заблокированы.

я взломал какой-то код, с которым я работал, и все \\\ в функции они сводят меня с ума. Если у кого-нибудь есть пример этого, я был бы очень признателен.

11 134

11 ответов:

PreparedStatements-это путь, потому что они делают невозможным внедрение SQL. Вот простой пример ввода пользователя в качестве параметров:

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

независимо от того, какие символы находятся в имени и электронной почте, эти символы будут помещены непосредственно в базу данных. Они никак не повлияют на инструкцию INSERT.

существуют различные методы набора для разных типов данных - какой из них вы используете, зависит от того, какие поля вашей базы данных. Например, если у вас есть целочисленный столбец в базе данных, вы должны использовать setInt метод. подготовленная документация перечисляет все различные методы, доступные для настройки и получения данных.

единственный способ предотвратить инъекцию SQL - это параметризованный SQL. Это просто невозможно построить фильтр, который умнее, чем люди, которые взламывают SQL для жизни.

поэтому используйте параметры для всех входных данных, обновлений и предложений where. Динамический SQL-это просто открытая дверь для хакеров, и это включает динамический SQL в хранимые процедуры. Параметризация, параметризация, параметризация.

Если действительно Вы не можете использовать Вариант Защиты 1: Подготовленные Операторы (Параметризованные Запросы) или Вариант Защиты 2: Хранимые Процедуры, Не создавайте свой собственный инструмент, используйте OWASP Enterprise Security API. Из OWASP ESAPI размещенный на Google код:

Не пишите свои собственные элементы управления безопасностью! Изобретение колеса, когда речь заходит о разработке элементов управления безопасностью для каждого веб-приложения или веб-службы приводит к потерянное время и огромные дыры в безопасности. Наборы инструментов OWASP Enterprise Security API (ESAPI) помогают разработчикам программного обеспечения защититься от недостатков проектирования и реализации, связанных с безопасностью.

для получения более подробной информации см. предотвращение SQL-инъекции в Java и SQL Injection Prevention шпаргалка.

обратите особое внимание на Вариант Защиты 3: Экранирование Всех Пользовательских Входных Данных что вводит OWASP ESAPI проект.)

(это ответ на комментарий OP под исходным вопросом; я полностью согласен с тем, что PreparedStatement является инструментом для этой работы, а не для регулярных выражений.)

когда вы говорите \n, вы имеете в виду последовательность \+n или символ? Если это \+n задача очень проста:

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

чтобы соответствовать одной обратной косой черте во входных данных, вы помещаете четыре из них в строку регулярного выражения. Чтобы поставить одну обратную косую черту на выходе, вы ставите четыре из них они в строке замены. Это предполагает, что вы создаете регулярные выражения и замены в виде строковых литералов Java. Если вы создаете их любым другим способом (например, читая их из файла), вам не нужно делать все это двойное экранирование.

если у вас есть символ перевода строки на входе, и вы хотите заменить его escape-последовательностью, вы можете сделать второй проход над входом с помощью этого:

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

или, может быть, вы хотите две обратные косые черты (я не слишком ясно на что):

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

PreparedStatements путь в большинстве, но не во всех случаях. Иногда вы окажетесь в ситуации, когда запрос или его часть должны быть построены и сохранены в виде строки для последующего использования. Проверьте SQL Injection Prevention шпаргалка на сайт OWASP для получения более подробной информации и API на разных языках программирования.

использование регулярного выражения для удаления текста, который может вызвать инъекцию SQL, звучит так, как будто оператор SQL отправляется в базу данных через Statement, а не PreparedStatement.

один из самых простых способов предотвратить инъекцию SQL в первую очередь заключается в использовании PreparedStatement, который принимает данные для замены в инструкцию SQL с помощью заполнителей, которые не полагаются на конкатенации строк для создания инструкции SQL для отправки в база данных.

дополнительные сведения Используя Подготовленные Операторы С Учебники Java было бы хорошим местом для начала.

подготовленные операторы являются лучшим решением, но если вам действительно нужно сделать это вручную, вы также можете использовать StringEscapeUtils класс из библиотеки Apache Commons-Lang. Он имеет escapeSql(String) метод, который вы можете использовать:

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

в случае, если вы имеете дело с устаревшей системой, или у вас слишком много мест для переключения на PreparedStatements слишком мало времени - т. е. если есть препятствие для использования лучшей практики, предложенной другими ответами, вы можете попробовать AntiSQLFilter

вам нужен следующий код ниже. На первый взгляд, это может выглядеть как любой старый код, который я составила. Однако то, что я сделал, это посмотреть на исходный код http://grepcode.com/file/repo1.maven.org/maven2/mysql/mysql-connector-java/5.1.31/com/mysql/jdbc/PreparedStatement.java. затем после этого я тщательно просмотрел код setString (int parameterIndex, String x), чтобы найти символы, которые он экранирует, и настроил это для моего собственного класса, чтобы его можно было использовать для цели, которые вам нужны. В конце концов, если это список символов, которые Oracle избегает, то знание этого действительно успокаивает безопасность. Возможно, Oracle нужно подтолкнуть, чтобы добавить метод, подобный этому, для следующего крупного выпуска 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 '2': /* 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();
    }
}

после поиска тестирования много решения для предотвращения sqlmap от SQL инъекции, в случае устаревшей системы, которая не может применять подготовленные statments каждый где.

Ява-безопасности-межсайтовых-межсайтовый скриптинг и SQL-инъекции теме БЫЛО РЕШЕНИЕ

я попробовал @ Richard s решение, но не работает в моем случае. я использовал фильтр

цель этого фильтра-обернуть запрос в собственный код обертка MyHttpRequestWrapper который преобразует:

параметры HTTP со специальными символами ( ,‘,...) в HTML коды через организацию.springframework.сеть.утиль.HtmlUtils.htmlEscape(…) метод. Примечание: существует аналогичный класс в Apache Commons : орг.апаш.палата общин.ленг.StringEscapeUtils.escapeHtml(...) в SQL инъекционные символы ( ‘ ,",...) через Apache Commons classe орг.апаш.палата общин.ленг.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;
    }
}

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");
    str = str.replace("\n", "\n");
    str = str.replace("\r", "\r");
    str = str.replace("\"", "\\"");
    str = str.replace("\x1a", "\Z");
    data = str;
  }
return data;

}