Действительно ли безопасно использовать ввод данных пользователем для регулярных выражений Python?

Я хотел бы позволить своим пользователям использовать регулярные выражения для некоторых функций. Мне любопытно, что последствия имеют передающий ввод данных пользователем к re.compile (). Я предполагаю, что нет никакого способа для пользователя дать мне строку, которая могла позволить им выполнить произвольный код. Опасности, о которых я думал:

  1. Пользователь мог передать вход, который повышает исключение.
    • Пользователь мог передать вход, который заставляет regex механизм занимать много времени или использовать большую память.

Решение 1. легко: исключения выгоды. Я не уверен, существует ли хорошее решение 2. Возможно, просто ограничение длины regex работало бы.

Есть ли что-либо еще, о чем я должен волноваться?

16
задан Skeletron 4 January 2010 в 07:58
поделиться

6 ответов

Я работал над программой, которая позволяет пользователям вводить свой собственный регекс, и вы правы - они могут (и делают) вводить регекс, который может занять много времени - иногда дольше, чем продолжительность жизни во Вселенной. Что еще хуже, при обработке регекса Python держит GIL, так что он будет зависать не только поток, на котором запущен регекс, но и всю программу.

Ограничение длины регекса не сработает, так как проблема заключается в обратном движении. Например, соответствие регекса r"(\S+)+x" на строке длины N, не содержащей "x", приведет к обратному отсчету 2**N раз. В моей системе это занимает около секунды против "a "*21 и время удваивается для каждого дополнительного символа, так что строка из 100 символов займет примерно 19167393131891000 лет (это приблизительная оценка, я ее не приурочил).

Для более подробной информации читайте книгу О'Райли "Обучение регулярным выражениям" - в ней есть пара глав по выполнению.

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

Другая вещь, на которую мы смотрели, это исправление re-модуля, чтобы поднять исключение, если он отступает слишком много раз. Это возможно, но требует смены источника на Python C и перекомпиляции, поэтому не переносится. Мы также представили патч для выпуска GIL при совпадении с питоновыми строками, но я не думаю, что он был принят в ядро (питон держит GIL только потому, что регекс может быть запущен против мутирующих буферов)

.
20
ответ дан 30 November 2019 в 17:39
поделиться

Компиляция регулярного выражения должна быть достаточно безопасной. Хотя то, во что оно компилируется, не является строго NFA (обратные ссылки означают, что оно не так чисто), оно все же должно быть вроде как простым для компиляции в.

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

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

редактирование: Как отмечает Дейв, очевидно, что глобальная блокировка интерпретатора удерживается во время регрессионного совпадения, что усложнит установку этого тайм-аута. Если это так, то единственным вариантом установки таймаута является запуск матча в отдельном процессе. Хотя это и не совсем идеально, но выполнимо. Я совсем забыл о мультипроцессорной обработке . Интерес представляет этот раздел об обмене объектами. Если вам действительно нужны жесткие ограничения, то здесь можно использовать отдельные процессы.

.
4
ответ дан 30 November 2019 в 17:39
поделиться

Нет необходимости использовать компилятор(), кроме случаев, когда необходимо повторно использовать много различных регулярных выражений. Модуль уже кэширует последние выражения.

Пункт 2 (при выполнении) может быть очень сложным, если разрешить пользователю вводить любые регулярные выражения. Можно сделать сложный регеxp с несколькими символами, как, например, знаменитый (x+x+)+y. Я думаю, что эта проблема еще не решена в общем виде. Обходным путем может быть запуск другого потока и его мониторинг, если он превысит допустимое время, kill поток и return с ошибкой.

.
1
ответ дан 30 November 2019 в 17:39
поделиться

Технически нет необходимости использовать re.compile() для выполнения операции регулярного выражения над строкой. На самом деле, метод компиляции часто может быть медленнее, если вы выполняете операцию только один раз, так как при начальной компиляции возникают накладные расходы.

Если вас беспокоит слово "компилировать", то избегайте его все вместе и просто передайте необработанное выражение в match, search и т.д. В любом случае, вы можете немного улучшить производительность вашего кода.

0
ответ дан 30 November 2019 в 17:39
поделиться
[

] Я действительно не думаю, что можно выполнить код, просто передав его в re.compile. Как я понимаю, re.compile (или любая другая регекс-система на любом языке) преобразует регекс-строку в []конечный автомат [] (DFA или NFA), и, несмотря на зловещее имя 'компилировать', она не имеет никакого отношения к выполнению любого кода. [

]
0
ответ дан 30 November 2019 в 17:39
поделиться

JPCache - приличная легкая библиотека кэширования.

-121--5045499-

Кэш запросов является определенным типом кэша 2-го уровня. То, что вы называете кэшем второго уровня, я бы предпочел назвать «кэшем объекта».

Комментарии к вашим предположениям:

  • Кэш запросов хорош в основном наряду с кэшем второго уровня (он же объект кэш).

Кэш запросов содержит только необработанные результаты запросов в качестве первичных ключей в режиме гибернации, id's. Он не содержит фактически гидратированных объектов. Это имеет смысл, так как при выполнении запроса с jdbc он только фактически возвращает гидратированные (заполненные) объекты при итерации по результирующему набору. Инструкция не обязательно верна. Если запрос очень сложен и, таким образом, выполнение занимает очень много времени, использование кэша запросов позволит сэкономить это время. Использование кэша запросов не экономит время, необходимое для загрузки объектов из базы данных.

  • Кэш запросов является рискованным, если база данных была изменена и она не была отражена для кэша

Это верно, но это не уникально для запроса кэша, то же самое верно для того, что вы называете кэшем 2-го уровня, но то, что обычно называется кэшем объекта.

Таким образом, мое первое предположение заключается в том, что Hibernate первый поиск в Кэш сеансов, затем на втором уровне Кэш. Верно ли это предположение?

Да, при загрузке объектов это поведение.

Я также предполагаю, что если объект (Foo) который отсутствует в кэше 2-го уровня, был изменен в базе данных, затем кэш запросов, будучи перекрестным сеансом soped, вернет неверное идентификаторы и, следовательно, неправильные объекты. Правильно ли это?

Да, это повлияет как на кэш объектов, так и на кэш запросов. Это вызывает беспокойство только в том случае, если база данных изменяется без перехода в режим гибернации. Вы можете смягчить последствия этого, установив тайм-аут кэша запросов.

Можно ли тогда сказать, что использование кэш запросов, включающих неизменяемая информация даже для не 2L кэшированные объекты, является ли это хорошей практикой? (например, запрос, который имеет предложение where содержит условие, которое всегда вернуть те же результаты, например "выбрать p.ser_num где p.id =? "при ser_num и id пары не меняются один раз создано)

Для таких объектов нет причин не использовать как кэш объектов, так и кэш запросов.

Да, кэш запросов не работает на уровне сеанса, или кэш уровня 1. Таким образом, причина, по которой при повторном выполнении запроса он снова попадает в базу данных. Он не помещает результат (набор идентификаторов) запроса в кэш сеанса.

-121--3375437-

Случайным пользователям гораздо проще дать им поднабор языка. Правила глоббинга оболочки, например, в fnmatch . Другим примером являются правила условий SQL LIKE.

Переведите язык пользователя в соответствующий regex для выполнения во время выполнения.

6
ответ дан 30 November 2019 в 17:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: