我們上一篇安裝的WAF來自另一位技術大神 趙舜東,花名 趙班長,一直從事自動化運維方面的架構設計工作。阿里雲MVP、華為雲MVP、中國SaltStack使用者組發起人 、新運維社群發起人。
雖然並非安全專業出身,但根據他的自述,邊學邊寫,只用了幾天的時間就將WAF寫出來了,並於2016年正式釋出到GitHub。
趙班長的WAF參考了Kindle大神寫的 ngx_lua_waf ,另一款基於 OpenResty 的非常優秀的開源WAF。
不得不向 章亦春(agentzh)、趙舜東(趙班長)和 Kindle 等所有開源前輩們致以最高的敬意,讓我等能有這麼多的學習和實踐資源,respect!
在真正走近WAF之前,還是有必要對 Lua 這個指令碼語言進行一番瞭解,因為所有的業務邏輯都是基於 Lua 實現的。
推薦兩個關於Lua的學習資源:
順便分享本人正在使用的Lua偵錯工具:網路硬碟連結
解壓後其中有兩個檔案:
我們回過頭,再來看看上一篇Nginx的組態檔中關於WAF參照的幾行關鍵程式碼:
lua_shared_dict limit 50m;
lua_package_path "/home/my/tools/waflib/?.lua";
init_by_lua_file "/home/my/tools/waflib/init.lua";
access_by_lua_file "/home/my/tools/waflib/access.lua";
這四個指令都來自 lua-nginx-module,用來實現對 Nginx 的每個 Worker 執行緒中 Lua 環境的設定和定義。
作用:宣告一個共用記憶體區域
層級:http
格式:lua_shared_dict <name> <size>
由於各 Worker 執行緒中的 Lua 環境相對是獨立的,無法共用資料,但在很多情況下,需要在不同的 Worker 之間共用資料,此時就可以通過該指令進行宣告。
此例中的 limit
就是宣告出來的一個共用變數,在 WAF 中的作用就是在 CC 攻擊檢測時判斷當前使用者的請求頻次是否超限進行攔截。
作用:設定 Lua 指令碼檔案的搜尋路徑。
;;
表示原始搜尋路徑。
層級:http
格式:lua_package_path <lua-style-path-str>
官網描述:設定由 set_by_Lua、content_by_Lua 等指定的指令碼使用的 Lua 模組搜尋路徑,它的預設值是LUA_PATH環境變數的內容或LUA的編譯預設值。
個人理解:在 Lua 中參照其他檔案時,比如 require 'config'
,就會將 config 替換掉路徑中的問號並嘗試查詢這個檔案並引入進來。
設定搜尋路徑引數時,還可以使用 $prefix
變數來表示當前 Nginx 的工作目錄,該目錄一般在啟動時通過 -p PATH
引數進行定義。
如果有多個搜尋路徑,可用 ;
分割。
作用:指定初始化組態檔。
層級:http
格式:init_by_lua_file <path-to-lua-script-file>
個人理解:該初始化組態檔僅在 Nginx 啟動時執行一次,主要用於對全域性變數進行預載入或預處理。
但經過實踐,在對本篇的 WAF 進行設定時,刪除該指令並未產生任何影響。
作用:請求存取階段處理。
層級:http, server, location, location if
格式:access_by_lua_file <path-to-lua-script-file>
個人理解:每個請求接入時,都會經過該檔案的處理,其作用類似於前置攔截器。
本篇的 WAF 在對請求進行檢查時,主要就是從這個檔案切入的。
lua-nginx-module 模組的官方檔案:https://github.com/openresty/lua-nginx-module
其中最重要的兩個部分:
再來看一下 waflib
的目錄清單:
/usr/local/openresty/lualib/resty/
的軟連線;再進入到 rule-config 目錄,檢視其中的檔案清單:
以第一個 args.rule 規則檔案為例,我們檢視一下具體內容:
\.\./
\:\$
\$\{
select.+(from|limit)
(?:(union(.*?)select))
having|rongjitest
sleep\((\s*)(\d*)(\s*)\)
benchmark\((.*)\,(.*)\)
base64_decode\(
(?:from\W+information_schema\W)
(?:(?:current_)user|database|schema|connection_id)\s*\(
(?:etc\/\W*passwd)
into(\s+)+(?:dump|out)file\s*
group\s+by.+\(
xwork.MethodAccessor
(?:define|eval|file_get_contents|include|require|require_once|shell_exec|phpinfo|system|passthru|preg_\w+|execute|echo|print|print_r|var_dump|(fp)open|alert|showmodaldialog)\(
xwork\.MethodAccessor
(gopher|doc|php|glob|file|phar|zlib|ftp|ldap|dict|ogg|data)\:\/
java\.lang
\$_(GET|post|cookie|files|session|env|phplib|GLOBALS|SERVER)\[
\<(iframe|script|body|img|layer|div|meta|style|base|object|input)
(onmouseover|onerror|onload)\=
該檔案定義了 22 條檢測規則,一行一個,熟悉正則的話會很容易看懂。
我們也可以根據實際情況新增新的規則。
4 個Lua檔案和 8 個規則檔案,這12個檔案就是這個WAF的全部,你就說巧妙不巧妙!
趙班長向我們展示了一個迷你WAF應該具備的基本能力,從程式碼上也能看出來,都是點到為止。
所以有必要進行一些簡單的優化。
本人優化之後的程式碼:點此下載
優化說明:
到這裡,就已經對 OpenResty 下的 WAF 從部署到使用有了全面瞭解了。
如果時間允許的話,真想繼續對 WAF 進行深層次的學習和客製化。
版權宣告: 本文為博主 網無忌 原創文章,歡迎轉載,但請務必標註原文連結。