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
找到 CALL SP_test 後方的 (.*)
找到 CALL SP_test 後方的 (.*)
但是 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 的值即可。
 

參考