A NullReferenceException
бросается, когда мы пытаемся получить доступ к свойствам нулевого объекта или когда значение строки становится пустым, и мы пытаемся получить доступ к строковым методам.
Например:
string str = string.Empty;
str.ToLower(); // throw null reference exception
Public Class Person {
public string Name { get; set; }
}
Person objPerson;
objPerson.Name /// throw Null refernce Exception
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 перечислены все доступные методы настройки и получения данных.
(Это ответ на комментарий OP по оригинальному вопросу, я полностью согласен с тем, что PreparedStatement является инструментом для этой работы, а не регулярных выражений.)
Когда вы говорите \n
, вы имеете в виду последовательность \
+ n
или фактический символ перевода строки? Если это \
+ n
, задача довольно проста:
s = s.replaceAll("['\"\\\\]", "\\\\$0");
Чтобы сопоставить одну обратную косую черту во входе, вы поместили четыре из них в строку регулярных выражений. Чтобы поставить обратную косую черту на выходе, вы поместили четыре из них в заменяющую строку. Предполагается, что вы создаете регулярные выражения и замены в виде литералов Java String. Если вы создаете их любым другим способом (например, прочитав их из файла), вам не нужно делать все это двойное экранирование.
Если у вас есть символ перевода строки на входе, и вы хотите чтобы заменить его на escape-последовательность, вы можете сделать второй проход через вход:
s = s.replaceAll("\n", "\\\\n");
Или, может быть, вам нужны две обратные косые черты (я не слишком понятен):
s = s.replaceAll("\n", "\\\\\\\\n");
От: [Источник]
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;
}
Если вы имеете дело с устаревшей системой или у вас слишком много мест, чтобы переключиться на PreparedStatement
s за слишком малое время, то есть, если есть препятствие для использования наилучшей практики, предлагаемой другими ответами, вы можете попробовать AntiSQLFilter
Используя регулярное выражение для удаления текста, которое может вызвать SQL-инъекцию, похоже, что оператор SQL отправляется в базу данных через Statement
, а не в PreparedStatement
.
Одним из самых простых способов предотвратить внедрение SQL в первую очередь является использование функции PreparedStatement
, которая принимает данные для замены в оператор SQL с использованием заполнителей, который не полагается на строку конкатенации для создания оператора SQL для отправки в базу данных.
Для получения дополнительной информации, Использование подготовленных выражений из Учебники по Java будут хорошим местом для начать.
Единственный способ предотвратить SQL-инъекцию - это параметризованный SQL. Просто невозможно создать фильтр, который умнее людей, которые взломают SQL для жизни.
Поэтому используйте параметры для всех входов, обновлений и где предложения. Динамический SQL - это просто открытая дверь для хакеров, которая включает динамический SQL в хранимых процедурах. Параметрирование, параметризация, параметризация.
PreparedStatements - это путь, который можно найти в большинстве, но не во всех случаях. Иногда вы оказываетесь в ситуации, когда запрос или его часть должны быть построены и сохранены в виде строки для последующего использования. Ознакомьтесь с Шифром для предотвращения инъекций SQL на сайте OWASP для получения более подробной информации и API-интерфейсов на разных языках программирования.
Подготовленные утверждения - лучшее решение, но если вам действительно нужно это сделать вручную, вы также можете использовать класс StringEscapeUtils
из библиотеки Apache Commons-Lang. Он имеет метод escapeSql(String)
, который вы можете использовать:
import org.apache.commons.lang.StringEscapeUtils;
…
String escapedSQL = StringEscapeUtils.escapeSql(unescapedSQL);
Если вы действительно не можете использовать Вариант защиты 1: Подготовленные утверждения (параметризованные запросы) или Вариант защиты 2: Хранимые процедуры , не создавайте собственный инструмент, используйте API-интерфейс OWASP Enterprise Security API . Из OWASP ESAPI , размещенного в Google Code:
Не записывайте свои собственные элементы управления безопасностью! Переосмысление колеса, когда дело доходит до разработки средств контроля безопасности для каждого веб-приложения или веб-службы, приводит к растрачиванию времени и массивным дырам в безопасности. Инструментарий OWASP Enterprise Security API (ESAPI) помогает разработчикам программного обеспечения защищать связанные с безопасностью недостатки проектирования и реализации.
blockquote>Подробнее см. В Предотвращение внедрения SQL в Java и Шифрование для предотвращения инъекций SQL .
Обратите особое внимание на Вариант защиты 3: Эвакуация всех входных данных пользователя , который вводит проект OWASP ESAPI ).
Ниже приведен следующий код. С первого взгляда это может выглядеть как старый код, который я составил. Тем не менее, я посмотрел исходный код для 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();
}
}
mysql-connector-java-xxx
команды case '\u00a5'
и case '\u20a9'
кажутся удаленными
– zhy
18 April 2016 в 11:22
После поиска много тестирования решения для предотвращения sqlmap из SQL-инъекции, в случае устаревшей системы, которая не может применять подготовленные статусы каждый раз.
java-security-cross-site-scripting- xss-and-sql-injection topic БЫЛО РЕШЕНИЕ
Я попробовал решение @Richard, но не работал в моем случае. Я использовал фильтр
Цель этого фильтра - обернуть запрос в собственную кодировку MyHttpRequestWrapper, которая преобразует:
параметры HTTP со специальными символами (& lt; ,>, ', ...) в HTML-коды через метод org.springframework.web.util.HtmlUtils.htmlEscape (...). Примечание. В Apache Commons есть аналогичный класс: org.apache.commons.lang.StringEscapeUtils.escapeHtml (...) символы ввода SQL (', ", ...) через Apache Commons classe org.apache.commons.lang.StringEscapeUtils. escapeSql (...)
blockquote><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; } }