2013-07-30 2 views
2

У меня есть система, которая анализирует поток данных и на основе подписки многих пользователей ей необходимо ее отфильтровать. Однако эти фильтры могут содержать регулярные выражения, и мне нужно сделать их достаточно безопасными, чтобы злоумышленники не могли вставлять регулярные выражения, которые целенаправленно дорогостоящие CPU, чтобы уничтожить службу.Каков наилучший подход для обработки большого количества пользовательских регулярных выражений

Я интересно, что лучший подход должен быть,

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

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

Есть ли лучший способ справиться с этим? Должен ли я тестировать регулярные выражения с использованием некоторых тестовых данных после создания подписки? Или, может быть, использовать отдельную очередь для каждого пользователя, который разбирается в другом потоке?

Кроме того, подходит другой подход, который приходит мне на голову, собирает статистику о том, сколько процессорного времени занимает каждый фильтр, и отключите их, которые слишком много едят, но на самом деле не справляются с «очень плохими» регулярными выражениями, которые могут нужно минут процессорного времени, чтобы закончить

Если кто-то интересно, я пишу это в C#, но этот вопрос является довольно общим и может применяться к любому языку

+0

Я думал о блокировке всех вложенных повторений, но я боюсь, что будет слишком много ложных срабатываний. Кроме того, он не будет блокировать такие вещи, как '/.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*^/' ('O (п^16) '). –

+0

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

+0

Переместите фильтрующую часть на клиент. –

ответ

4

Поскольку вы используете C#, вам не нужно откручивать новый поток. Конструктор Regex имеет overload, что позволяет установить тайм-аут . Если регулярное выражение занимает слишком много времени, оно прерывается и бросает RegexMatchTimeoutException.

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

Другое дело, что было бы полезно сделать, если регулярные выражения больше, чем одноразовые использования, равны компиляции регулярных выражений. Регулярные выражения в C# поддерживают предварительную компиляцию для ускорения будущих матчей.

+0

Ничего себе, не знал, что ... Думаю, я соберу несколько ответов, это полезная информация – Petr

+0

К сожалению, это доступно с .Net 4.5 :(Кажется, это слишком ново для меня (на целевом сервере у меня есть моно) – Petr

+0

@ Петр. Я не знаю, насколько поддерживается многомодовый движок Mono, но компиляция регулярного выражения все равно будет применима, и использование пула потоков также будет работать. –

1

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

1

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

  • Пользователь хочет добавить фильтр X с регулярным выражением.
  • Приложение должно запускать этот фильтр по предопределенному набору данных.
  • Если этот пробег занимает более Y миллисекунд, не позволяйте его добавлять.
  • Пользователям с более высоким рейтингом (платный сервис, лояльным пользователям, ...) могут быть разрешены более агрессивные фильтры (более миллисекунды обработки).
+0

Важно, чтобы пользователи не знали тестовых данных. Ибо, если злоумышленник знает, что вы будете тестировать на «foo», он изменяет свое вредоносное регулярное выражение X на 'foo | X' – Ingo

+0

@Ingo Пользователи не должны знать набор данных; Приложение это знает. – Yousf

+1

Еще лучше генерирует случайные данные теста. – Ingo

1

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

Таким образом, у вас нет накладных расходов на запуск новых потоков все время, но они все равно могут убивать те, которые занимают слишком много времени.

Смежные вопросы