2010-01-04 41 views
14

我想讓我的用戶對某些功能使用正則表達式。我很好奇將用戶輸入傳遞給re.compile()的含義。我認爲用戶無法給我一個可以讓他們執行任意代碼的字符串。我曾經想到的危險是:使用Python的正則表達式的用戶輸入安全嗎?

  1. 用戶可以傳遞引發異常的輸入。
    • 用戶可以通過導致正則表達式引擎花費很長時間或使用大量內存的輸入。

1。解決辦法很簡單:捕捉異常。我不確定是否有一個好的解決方案2.也許只是限制正則表達式的長度將工作。

還有什麼我需要擔心?

回答

17

我已經開發了一個程序,允許用戶輸入他們自己的正則表達式,並且你是對的 - 他們可以(並且確實)輸入可能需要很長時間才能完成的正則表達式 - 有時比宇宙的壽命更長。更糟糕的是,在處理正則表達式時,Python持有GIL,因此它不僅會掛起正在運行正則表達式的線程,還會掛起整個程序。

限制正則表達式的長度不起作用,因爲問題是回溯。例如,將正則表達式r"(\S+)+x"與不包含「x」的長度爲N的字符串進行匹配將會回溯2 ** N次。在我的系統上,這需要大約一秒鐘的時間來匹配"a"*21,並且每增加一個字符的時間就會翻倍,所以100個字符的字符串需要大約19167393131891000年才能完成(這是一個估計,我沒有計時)。

欲瞭解更多信息,請閱讀O'Reilly的書「掌握正則表達式」 - 這有幾個章節的表現。

編輯 爲了避開這一點,我們寫道,試圖追上並拒絕一些較爲明顯的退化情況正則表達式分析功能,但不可能讓所有的人。

我們看到的另一件事是修補re模塊,以便在回溯太多次時引發異常。這是可能的,但需要更改Python C源代碼並重新編譯,因此不可移植。我們還提交了一個補丁來釋放與Python字符串匹配的GIL,但我認爲它不被接受進入核心(python只包含GIL,因爲正則表達式可以針對可變緩衝區運行)。

+8

+1「(這是一個估計,我沒有計時)」 – 2010-01-04 11:41:23

+1

我想我可以產卵另一個過程然後殺了它,如果超時後超時? – Skeletron 2010-01-04 17:08:16

+0

產卵和殺戮將會奏效,但爲每場比賽增加相當的開銷。是否可以接受的價格取決於你。 – 2010-01-04 18:25:34

0

我真的不認爲這是可能通過它傳遞到re.compile簡單地執行代碼。我的理解是,re.compile(或以任何語言的任何正則表達式系統)正則表達式字符串轉換爲finite automaton(DFA或NFA),儘管不祥的名字「編譯」它無關的任何代碼的執行。

0

您在技術上不需要使用re.compile()來對字符串執行正則表達式操作。事實上,如果您只執行一次操作,那麼編譯方法通常會比較慢,因爲與初始編譯相關的開銷很大。

如果您擔心「編譯」這個詞,那麼請一起避免它,並簡單地將原始表達式傳遞給matchsearch等。您可能會稍微提高代碼的性能。

+1

我認爲這是有點除了點。爲了執行實際的搜索,無論如何,匹配必須執行編譯步驟,這是OP所擔心的。 – wds 2010-01-04 09:49:22

1

除非需要重用大量不同的正則表達式,否則不需要使用compile()。模塊已經緩存了最後一個表達式。

如果您允許用戶輸入任何正則表達式,那麼點2(執行時)可能會非常困難。你可以製作一個複雜的幾個字符的正則表達式,比如着名的(x+x+)+y之一。我認爲這是一個尚未得到普遍解決的問題。 一種解決方法可能是啓動一個不同的線程和監視它,如果它超過了允許的時間,殺掉線程,並返回一個錯誤。

3

編譯正則表達式應該是相當安全的。雖然它編譯成的不是嚴格的NFA(反向引用意味着它不是很乾淨),但它仍然可以直接編譯進去。

現在對性能的特點,這是另一個問題完全。由於回溯,即使是小規則表達式也可能具有指數時間特性。定義一些特徵子集可能會更好,並且只支持自己翻譯的非常有限的表達式。

如果您確實想要支持常規正則表達式,您必須信任用戶(有時是選項)或限制所用空間和時間。我相信所用空間僅由正則表達式的長度決定。

編輯:正如戴夫指出的,顯然全局解釋器鎖在正則表達式匹配期間被保留,這將使得設置超時更困難。如果是這種情況,則設置超時的唯一選項是在單獨的進程中運行匹配。雖然不太理想,但它是可行的。我完全忘了multiprocessing。興趣點是共享對象this section。如果你真的需要嚴格的約束,單獨的流程就可以走到這裏。

+1

使用單獨的線程來實現超時不起作用,因爲python在進行比賽時持有GIL - 請參閱我的答案。即使你修補重新釋放GIL,你也需要添加一些殺死運行正則表達式的線程 - 這不是小事! – 2010-01-04 10:12:13

+0

我的錯誤,那真是令人煩惱。我會編輯我的答案,使其更模糊但可能。 – wds 2010-01-05 08:48:30

6

對於臨時用戶來說,給他們一個子集語言要簡單得多。例如,外殼的匹配規則爲fnmatch。 SQL LIKE條件規則是另一個例子。

將用戶的語言翻譯成合適的正則表達式,以便在運行時執行。

+0

+1唯一安全的方式 – bobince 2010-01-04 14:54:35

相關問題