type
status
date
slug
summary
tags
category
icon
password
需求
原始內容如下:
希望經過 logstash pipeline 處理成:
注意必須識別到
CALL
才能進行替換,同時必須保留 SP
名稱。問題
原本是希望用
muate filter
中的 gsub
功能來實現,gsub 可以將 field 內容依據正則匹配來進行替換。gsub 範例:
原始內容:
logstash pipeline 設定:
output 結果:
在需求中為了保留 SP 名稱要使用到正則表達式中的
lookbehind assertions
也就是 (?<=exp2)exp1
的表達式,這表示會查找 exp2
後面的 exp1
。
但是 SP 名稱是不固定的,因此需要將原本的
(?<=CALL SP_test)
調整為 (?<=CALL \S*)
,但是卻會引發錯誤:這是因為許多正則表達式的 library 都對於
lookbehind assertions
都有一些或多或少的限制。最常見的限制就是不允許不固定長度的 lookbehin,也就是說不能使用 +
、 *
或 {1,}
……等。其中一個原因是為了避免時間複雜度過高的正則表達式,除了過於消耗資源也可能會被應用於 ReDOS 攻擊。
ReDOS 攻擊:基於 NFA 引擎編寫的正則表達式有缺陷時,攻擊者可以透過相應的 input 來達到消耗 server 大量資源從而達到 DOS 攻擊的效果。
正則表達式引擎簡述:
- DFA:以文本和正則匹配,因此文本中的每個字符只會掃描一次,因此速度較快,但支援特性少,例如:awk、MySQL……等。
- NFA:以正則去和文本匹配,因此文本中的每個字符可能會掃描多次,速度較慢,但支援特性多,例如:sed、python、java……等。
備註
當然還有其他的正則引擎,例如:Golang 官方的 regexp pachage 使用 RE2 engine 也不受 ReDOS 影響,因為其時間複雜度是線性的也就是 O(n),但是相應的不支持某些特性 (如:lookaround, lookbehind ……等)。
此外程式語言也會隨著版本對於一些常見的 ReDOS 做預防和改善。
額外知識:不同語言對於 lookbehind 的支持程度
- Golang:官方 regexp package 為了保證 O(n) 的時間複雜度,因此不支持 lookbehind (也不支持 lookaround)。
- 備註:非官方的 regexp2 package 有支持。
- Javascript:ES2018 開始支持 lookbehind。
- Python:lookbehind 要求必須為固定長度。
- 可以:(?<=abc)、(?<=a|b)
- 不可以:(?<=a*)、(?<=a{3,4}) 、(?<=a{3,})
- Java:從 Java8 開始可以使用固定長度或指定上限的 lookbehind
- 可以:(?<=abc)、(?<=a|b)、(?<=a{3,4})
- 不可以:(?<=a*) 、(?<=a{3,})
- .NET 框架:完全支持
經過一番確認,logstash pipeline 就連
{1,10}
(指匹配 1~10 次)都不支持,完全只支援固定長度,因此只能放棄這條路。解決方案
先透過
gork
進一步將 CALL SP 語句拆解出兩個 field:- storedProcedureName:表示 SP 名稱,捕獲規則是
CALL
後方到(
之前的所有字元。
- storedProcedureValue :表示 SP 參數,捕獲規則是 SP 名稱後
(
和)
之間的所有字元。
之後再用 mutate filter 中的
update
替換掉 query field 的值即可。