Миграция StringEscapeUtils.escapeSql из commons.lang

Я начал мигрировать с commons.lang 2 на commons.lang3.

Согласно https://commons.apache.org/proper/commons-lang/article3_0.html

StringEscapeUtils.escapeSql

Это был вводящий в заблуждение метод, обрабатывающий только самые простые из возможных случаев SQL. ›Поскольку Ланг не занимается SQL, поддерживать этот метод не имело смысла.

Поймите это, но что рекомендуется использовать вместо него?

Пояснение

Можете ли вы порекомендовать третью сторону, которая выполняет простой escapeSql, аналогичный StringEscapeUtils.escapeSql?


person Michael    schedule 19.08.2015    source источник
comment
Опишите свой вариант использования. Самым простым из них будет запуск запросов к базе данных, и для этого вам обычно не нужно экранировать какой-либо SQL (вы можете и должны использовать переменные связывания).   -  person Thilo    schedule 19.08.2015
comment
Почему вы хотите это сделать? Это кажется плохой идеей, поэтому я могу понять, почему этот метод был удален.   -  person Thilo    schedule 19.08.2015
comment
Простой вариант использования... PreparedStatement не работает, если у вас есть параметры, необходимые в предложении order by.   -  person Nathan Crause    schedule 09.06.2021
comment
@NathanCrause: Хм. Что это за СУБД? Можно ли обойти это, обернув запрос во встроенное представление/подзапрос, чтобы выражение, которое должно быть упорядочено, стало столбцом? Возможно, стоит открыть новый вопрос для этого конкретного примера.   -  person Thilo    schedule 19.07.2021
comment
@Thilo, это интересная идея, которую я не рассматривал. С чисто технической точки зрения это похоже на переделку чего-то, что не нужно переделывать. Чтобы ответить на первый вопрос, это MariaDB. (Это не по выбору, кстати, я хотел PostgreSQL).   -  person Nathan Crause    schedule 26.07.2021


Ответы (3)


Из Javadocs:

В настоящее время этот метод только превращает одинарные кавычки в двойные одинарные ("McHale's Navy" => "McHale's Navy").

Это был код метода:

  /**
675         * <p>Escapes the characters in a <code>String</code> to be suitable to pass to
676         * an SQL query.</p>
677         *
678         * <p>For example,
679         * <pre>statement.executeQuery("SELECT * FROM MOVIES WHERE TITLE='" + 
680         *   StringEscapeUtils.escapeSql("McHale's Navy") + 
681         *   "'");</pre>
682         * </p>
683         *
684         * <p>At present, this method only turns single-quotes into doubled single-quotes
685         * (<code>"McHale's Navy"</code> => <code>"McHale''s Navy"</code>). It does not
686         * handle the cases of percent (%) or underscore (_) for use in LIKE clauses.</p>
687         *
688         * see http://www.jguru.com/faq/view.jsp?EID=8881
689         * @param str  the string to escape, may be null
690         * @return a new String, escaped for SQL, <code>null</code> if null string input
691         */
692        public static String escapeSql(String str) {
693            if (str == null) {
694                return null;
695            }
696            return StringUtils.replace(str, "'", "''");
697        }

Таким образом, вы можете легко заменить метод простым вызовом String#replace.

Однако есть причина, по которой метод был удален. Это было действительно полусырое, и я не могу придумать вескую причину, по которой вы хотели бы использовать его. Например, для выполнения запросов JDBC вы можете и должны использовать переменные связывания вместо того, чтобы пытаться интерполировать и экранировать строковые литералы.

person Thilo    schedule 19.08.2015
comment
На самом деле существует вариант использования: экранирование частей оператора SQL, которые нельзя параметризовать с помощью переменных связывания. Например. само имя таблицы: stackoverflow.com/q/1208442/274677 - person Marcus Junius Brutus; 24.01.2017
comment
@MarcusJuniusBrutus: я бы не стал рассчитывать на то, что там будут использоваться те же правила экранирования. И если вы используете такие вещи, как пробелы или кавычки в именах объектов схемы, вы уже напрашиваетесь на неприятности. - person Thilo; 24.01.2017
comment
@Thilo, как насчет этого варианта использования: PreparedStatement не работает, если у вас есть параметры, необходимые в предложении order by. - person Nathan Crause; 09.06.2021
comment
@NathanCrause не уверен, что ты имеешь в виду. Если вы хотите иметь переменные имена столбцов в ORDER BY abc DESC, то да, как Маркус заметил об именах таблиц, параметры привязки нельзя использовать для имен объектов схемы, только для значений. - person Thilo; 09.06.2021
comment
@Thilo, в этом суть - в системе, над которой я работал, было предложение order by, содержащее передаваемые значения (порядок сортировки основывался на подсчете очков в зависимости от того, находилась ли предоставленная строка в начале или в конце значения столбца). Поэтому я не могу придумать вескую причину, это совершенно неуместный момент только потому, что вариант использования не может быть понят в какой-то момент, из этого не следует, что для него НЕТ варианта использования. - person Nathan Crause; 18.07.2021
comment
@NathanCrause И вам нужно экранирование строкового литерала для этого? Похоже, вы все еще можете использовать переменные связывания. Думает, что CASE WHEN x LIKE '%' || ? THEN поддерживает это. - person Thilo; 19.07.2021
comment
@ Тило, ты ошибаешься. ? в этом случае не обрабатывается. Вообще. ЛЮБЫЕ ? в предложении order by не обрабатывается. - person Nathan Crause; 26.07.2021

Если вы используете соединение JDBC, подготовьте оператор с такими параметрами, как:

con.prepareStatement("INSERT INTO table1 VALUES (?,?)");
pstmt.setInt(1, 200);
pstmt.setString(2, "Julie");
pstmt.executeUpdate();

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

На этот вопрос уже был дан ответ: Java - escape-строка для предотвращения внедрения SQL

person Matjaž Pečan    schedule 19.08.2015
comment
Но это не работает для всех предложений SQL. Как я уже упоминал в других комментариях здесь, это не сработает, если у вас есть параметры, присутствующие в вашем заказе. - person Nathan Crause; 09.06.2021
comment
Это также работает, если вы используете JPA/Hibernate, когда вам нужно работать с собственным запросом. Вместо этого используйте подготовленный оператор. java Query q = entityManager.createQuery("SELECT * FROM people WHERE name = ?") ; q.setParameter(1, "Julie") - person kosgeinsky; 03.07.2021

OWASP предлагает API под названием ESAPI, который предоставляет некоторые из этих функций. проверить это.

person bub    schedule 27.06.2016
comment
Вот пример и ссылка на сайте, которые объясняют, как использовать этот API, а также обсуждение других подходов. ESAPI.encoder().encodeForSQL(new OracleCodec(), queryparam); cheatsheetseries.owasp.org/cheatsheets/ - person David Bradley; 19.02.2021