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

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

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

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 метод. документация PreparedStatement перечисляет все различные методы, доступные для настройки и получения данных.


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

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


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

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

дополнительные сведения см. В разделе предотвращение SQL-инъекции в Java и SQL инъекции профилактики шпаргалка.

обратите особое внимание на Защита Вариант 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 инъекции профилактики шпаргалка на сайт 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-инъекции, в случае устаревшей системы, которая не может применять подготовленные состояния везде.

java-безопасность-межсайтовые скрипты-XSS-и-sql-инъекции тема РЕШЕНИЕ

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

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

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

}