我有一个解析数据流的系统,并且基于许多用户的订阅,它需要对其进行过滤。但是,这些过滤器可以包含正则表达式,我需要使其足够安全,以便恶意用户无法插入有目的的CPU昂贵的正则表达式来破坏服务。
我想知道最好的方法应该是什么,
在我制作的另一个程序中,我通过生成执行正则表达式搜索的新线程来处理此问题,如果此线程的运行时间超过限制,则会被终止并且条目被阻止。
然而,这个系统可能每分钟处理数千条记录,我无法想象我会为每一条记录生成一个新线程(实际上我需要为每个条目循环所有订阅,因此它可能有数十万个线程每一分钟。
有没有更好的方法来处理这个问题?创建订阅后,我应该使用一些测试数据来测试正则表达式吗?或者可能为每个在不同线程中解析的用户使用单独的队列?
另外一种不同的方法是收集每个过滤器占用多少CPU时间的统计信息,并禁用过多吃掉的那些,但这并不能真正处理可能需要的“非常糟糕”的正则表达式完成CPU时间的分钟
如果有人感兴趣,我会用c#编写,但这个问题相当通用,适用于任何语言
答案 0 :(得分:4)
由于您使用的是C#,因此无需剥离新线程。 Regex
构造函数有一个overload,可让您设置超时。如果正则表达式花费的时间太长,它将中止并抛出RegexMatchTimeoutException。
对于没有内置超时的正则表达式引擎,您可能只能通过生成一个线程并重用它来管理,或者让线程池为您分配线程
如果正则表达式不仅仅是一次性使用,那么值得做的另一件事是编译正则表达式。 C#中的正则表达式支持预编译以加速未来的匹配。
答案 1 :(得分:1)
如果您愿意实施自己的正则表达式引擎(或查找库),请使用Thompson的NFA构造方法并限制每个自动机中的状态数(或者,为了更好地理解用户,正则表达式的长度,高度相关)。匹配算法的性能比回溯算法更可预测。
答案 2 :(得分:1)
我认为,如果您在用户添加新过滤器时评估运行此正则表达式的成本会更好。例如:
答案 3 :(得分:1)
你真的不需要为每个正则表达式生成一个线程...而是创建工作线程,通过循环中的剩余正则表达式工作,在每次迭代时记录循环的开始。然后,使用您以前的解决方案来杀死花费太长时间的工作线程,禁用正则表达式并重新生成工作线程。
这样,你没有一直开始新线程的开销,但是仍然可以杀掉那些花费太长时间的线程。