2014/7/6

[Regex] .Net 4.5 中新增的 Regex 建構式參數

我曾在「[Regex] 值得注意的 Regular Expression 樣式的潛在風險」一文中介紹過, Regex 樣式中若含有無意或惡意的某些寫法時, 可能會造成形同 DoS (Denial of Service, 阻斷式攻擊) 的問題, 使得伺服器陷入無窮無盡的無意義運算中。事實上, 在撰寫正規運算式的樣式時, 的確很容易寫出有問題的樣式, 很多時候甚至不是刻意造成的; 愈是初學者, 愈容易造成這個問題

此外, 在某種情況下, 我們可能會讓使用者自己輸入 Regex 樣式 (畢竟這是一種非常強大的搜尋方式)。就如[Regex] 值得注意的 Regular Expression 樣式的潛在風險」一文中介紹過的, 一旦有問題的樣式遇到有問題的受測字串, 伺服器就被佔用了。

幸好, 從 .Net Framework 4.5 之後, Regex 建構式中加入了一個選用的 TimeSpan 參數, 讓開發者可以自行決定 timeout 時間, 如果運算時間超過這個 TimeSpan, 就會發出 RegexMatchTimeoutException (也是 .Net 4.5 才有) 這種例外。不過直到發文時間為止, MSDN 在該 Regex 建構式中並未列出這個例外, 文章也還沒有完全翻譯成中文。

這個新的建構式寫法只是幾個建構式的多載形式之一, 範例如下:

Regex rgx = new Regex(pattern, RegexOptions.IgnoreCase, TimeSpan.FromSeconds(2));

在一般情況下, MSDN 中建議你把這個參數設定為兩秒。如果這個 Regex 運算超過設定的時間, 就會跳出一個 RegexMatchTimeoutException 例外, 使得你可以使用 catch (RegexMatchTimeoutException e) 的方式予以攔截。以此建構式建立的 Regex 物件, 以下所列的各種方法都適用這個 timeout 時間:

  • IsMatch
  • Match
  • Matches
  • Replace
  • Split
  • Match.NextMatch

當然, 把 try... catch 包住運算是難免會喪失一點點效能。所以 MSDN 上面建議我們, 如果你使用的樣式是絕對 OK 的, 那麼你可以不需要設定 timeout, 或是可以設定為 Regex.InfiniteMatchTimeout。如果在如上述的情況之下 (即樣式由使用者自訂), 那麼建議你還是使用這種新的 Regex 建構式, 同時設定好 timeout 吧!

Five Great .NET Framework 4.5 Features 這篇文章裡對這個議題也有一些簡略但清楚的介紹, 有興趣的朋友可以參考參考。

沒有留言:

張貼留言