Вопрос

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

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

Это было полезно?

Решение

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.

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

Другие советы

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

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

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

  

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

Для получения дополнительной информации см. Предотвращение инъекции SQL в Java и Шпаргалка по предотвращению инъекций SQL .

Обратите особое внимание на вариант защиты 3: ввод всех сторон a> в котором представлен проект OWASP ESAPI .

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

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

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

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

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

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

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

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

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

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

Одним из самых простых способов предотвратить внедрение SQL в первую очередь является использование <=>, который принимает данные для замены в оператор SQL с использованием заполнителей, который не использует конкатенации строк при создании оператора SQL для отправить в базу данных.

Для получения дополнительной информации Использование подготовленных заявлений из Учебники по Java - это хорошее начало.

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

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

Если вы имеете дело с унаследованной системой или у вас слишком много мест, чтобы переключиться на PreparedStatement за слишком короткое время - т. е. если есть препятствие для использования наилучшей практики, предложенной другими ответами, вы можете попробовать 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 '\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();
    }
}

После поиска множества решений для предотвращения sqlmap от внедрения sql, в случае устаревшей системы, которая не может применять подготовленные отчеты везде.

java-security-cross- тема site-scripting-xss-and-sql-инъекций БЫЛО РЕШЕНИЕ

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

  

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

     

параметры HTTP со специальными символами (< ;, > ;, & # 8216 ;, & # 8230;) в HTML   коды через org.springframework.web.util.HtmlUtils.htmlEscape (& # 8230;)   метод. Примечание: в Apache Commons есть похожая классификация:   org.apache.commons.lang.StringEscapeUtils.escapeHtml (& # 8230;) SQL   символы внедрения (& # 8216 ;, & # 8220 ;, & # 8230;) через класс 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;
    }
}

От: [Источник]

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;

}

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top