使用OpenResty搭建WAF應用

使用OpenResty搭建WAF應用

OpenResty簡介

OpenResty是將Nginx與 Lua粘合的高性能 Web 平臺,其內部集成了大量精良的 Lua 庫、第三方模塊等。用于方便地搭建高并發、擴展性極高的動態Web 應用、Web 服務和動態網關。從聽說到使用了OpenResty之后,感覺這是瑞士軍刀,應用實在太廣泛。

我們公司目前沒有專門的安全工程師,安全的一些工作就落到我們運維工程師頭上,遇到安全問題就找到我們身上了,因此我想做一個web應用防火墻,讓開發人員不用考慮安全問題只關心業務開發;因此就考慮開發WAF來解決現在遇到的問題。

WAF簡介

WAF就是web應用防火墻,是對網站進行安全防護的。一個http/https的請求,包含數據: url、get參數、post參數、協議版本/method/host/agent/cookie等http請求頭。 如下圖所示:

而WAF就可以對請求中的參數、訪問頻率進行安全檢查(正則匹配為主),觸發危險操作的請求,就進行攔截、記錄操作。 當然WAF解決是還是web安全1.0和2.0的問題。對應業務邏輯本身WAF目前是不能通用的進行防護的。

WEB安全1.0

在1.0時代下,攻擊是通過服務器漏洞(IIS6溢出等)、WEB應用漏洞(SQL注入、文件上傳、命令執行、文件包含等)屬于服務器類的攻擊,該類型漏洞雖然經歷了這么多年,很遺憾,此類漏洞還是存在,并且重復在犯相同的錯誤。

WEB安全2.0

隨著社交網絡的興起,原來不被重視的XSS、CSRF等漏洞逐漸進入人們的視野,那么在2.0時代,漏洞利用的思想將更重要,發揮你的想象,可以有太多可能。

WEB安全3.0

同開發設計模式類似(界面、業務邏輯、數據),3.0將關注應用本身的業務邏輯和數據安全,如密碼修改繞過、二級密碼繞過、支付類漏洞、刷錢等類型的漏洞,故注重的是產品本身的業務安全、數據安全。

WAF設計、編碼

我設計的WAF過濾流程,只是根據我的理解來設計他的處理流程,不一定是最合理的,但是解決了我們現在遇到的問題。整個設計是在Nginx執行的相應階段完成一些相應的動作,如在init階段完成數據初始化、rewrite階段暫時沒用,預計未來跳轉使用(如驗證碼、set cookie等)、access階段實施攔截防護(大多數過濾在這完成)、body_filter階段進行響應內容的替換(如非法關鍵詞替換)。

init階段

在nginx初始化階段,我們可以初始化如ip黑白名單;初始化ip計數器;此處我們用到了幾個共享字典來存儲這些數據(如1MB大約存ip數量1000個)。

lua_shared_dicttoken_list 20m;??? # token存放

lua_shared_dictcount_dict 5m;???? #用于攔截計數數據的保存

lua_shared_dictconfig_dict 5m;??? #保存config中部分配置

lua_shared_dictip_dict 30m;?????? #用于記錄黑、白名單ip

lua_shared_dictlimit_ip_dict 100m;?? #用于 IP 訪問計數統計

在初始化階段,會讀取全局配置文件config.json和規則配置文件xxx_Mod.json,存放到config_dict中;其次,讀取配置的ip黑白名單存放到ip_dict;然后定義一些公共函數如sayHtml,sayFile,sayLua等等。

access階段

我們主要的攔截就在該階段操作的,整體的防護分為13個步驟進行分層防護的,如下圖所示。

0、realIpFrom_Mod==>獲取用戶真實IP:獲取用戶真實ip 在一些網絡場景下,用戶真實ip在http頭中,所以我們先要把真實ip取出來;

1、ip_Mod==>ip黑白名單的過濾(黑白名單):ip白名單后續的規則都跳過了,請求繼續走;ip黑名單,就是在應用層進行攔截,請求到這里就停了,不會到后端了;

2、host_method_Mod==>host&method過濾(白名單):這里就是域名準入,和method的準入了,可以配置允許的host,允許的method;

3、app_Mod==>自定義過濾動作:這里提供的幾個動作是:返回字符串、返回文件內容、動態執行lua腳本、記錄log、匹配白名單(ip,args參數);基本匹配的是:host、url在后續的場景中我在舉一些例子;

4、referer_Mod==>referer規則過濾(白名單):一些圖片資源的防盜鏈,站外的CSRF就是通過referer來過濾的;

5、url_Mod==>url過濾(黑、白名單):

“\.(svn|git|htaccess|bash_history)” —敏感文件、目錄、備份文件黑名單攔截;

“\.(css|js|flv|swf|woff|txt)$” –靜態資源文件白名單,這樣后續的過濾規則都會跳過,減少總的匹配次數,提高效率;以及訪問頻率統計時,去掉這些靜態文件的統計;

6、header_Mod==>header過濾(黑名單):一些掃描器,爆破工具,黑客工具有時在http頭中會有一些標記,這里我們就可以過掉;

{

"state": "on",

"url":["*",""],

"hostname":["*",""],

"header":["Acunetix_Aspect","*",""]

},

--掃描器 wvs 的標記

{

"state": "on",

"url":["*",""],

"hostname":["*",""],

"header": ["X_Scan_Memo","*",""]

}

--掃描器 Scan 的標記

7、useragent_Mod==>user-agent過濾(黑名單):這里是過濾一些常見黑客工具,壓測工具等;

havij|sqlmap|nmap|HTTrack...

8、cookie_Mod==>cookie過濾(黑名單):這里是對cookie進行SQL注入、XSS、遍歷、敏感文件讀取等一些規則的過濾;

9、args_Mod==>GET參數過濾(黑名單):這里是對args參數進行SQL注入、XSS、遍歷、敏感文件讀取等一些規則的過濾;

if config_is_on("args_Mod") then

local args_mod =getDict_Config("args_Mod")

local args =ngx.unescape_uri(ngx.var.query_string)

if args ~= "" then

for i,v in ipairs(args_mod) do

if v.state == "on" then

if remath(host,v.hostname[1],v.hostname[2])then

if remath(args,v.args[1],v.args[2]) then

Set_count_dict("args_deny count")

action_deny()

break

end

end

end

end

end

end

看一下代碼,對于參數污染這種繞WAF的方式,還有url編碼繞過方式也是無法繞過的,代碼中首先進行了轉碼、在取整個args,而不是一個一個取在拼接上;

10、post_Mod==>post參數過濾(黑名單):這里是對post參數進行SQL注入、XSS、遍歷、敏感文件讀取等一些規則的過濾;

localfunction get_postargs()

ngx.req.read_body()

local data = ngx.req.get_body_data() --ngx.req.get_post_args()

if not data then

local datafile =ngx.req.get_body_file()

if datafile then

local fh, err = io.open(datafile,"r")

if fh then

fh:seek("set")

data = fh:read("*a")

fh:close()

end

end

end

return ngx.unescape_uri(data)

end

if config_is_on("post_Mod") and method == "POST" then

--debug("post_Mod is on")

local post_mod =getDict_Config("post_Mod")

local postargs = get_postargs()

if postargs ~= "" then

for i,v in ipairs(post_mod) do

if v.state == "on" then

--debug(i.." post_modstate is on")

if remath(host,v.hostname[1],v.hostname[2]) then

if remath(postargs,v.post[1],v.post[2]) then

Set_count_dict("post_deny count")

debug("post_Mod :"..postargs.."No : "..i,"post_deny",ip)

action_deny()

break

end

end

end

end

end

end

代碼中是取整個body的,而不是通過ngx.req.get_post_args(),且最后也轉碼了,所以通過參數污染、url轉碼是不能繞過的;

11、network_Mod==>訪問頻率過濾(頻率黑名單):先看一個配置:

--單個URL的頻率限制

--因為一個網站一般情況下容易被CC的點就那么幾個

{

"state": "on",

"network":{"maxReqs":10,"pTime":10,"blackTime":600},

"hostname":[["101.200.122.200","127.0.0.1"],"table"],

"url":["/api/time",""]

}

--限制整個網站的(范圍大的一定要放下面)

{

"state": "on",

"network":{"maxReqs":30,"pTime":10,"blackTime":600},

"hostname":[["101.200.122.200","127.0.0.1"],"table"],

"url":["*",""]

}

--限制ip的不區分host和url

{

"state": "on",

"network":{"maxReqs":100,"pTime":10,"blackTime":600},

"hostname":["*",""],

"url":["*",""]

}

相對來說比較靈活,可以配置某個url的ip訪問頻率,以及在前面提到過,一些靜態文件css/js/img文件是可以不計數的。

body_filter階段

12、replace_Mod==>應答內容的替換:這里就是對返回內容的動態替換的功能,比如替換一些非法關鍵詞等。

場景應用

1、簡單的正則添加:如我們需要過濾以.sql結尾的請求URL,那么就在url_Mod中設置

{

"state": "on",

"hostname": [

"*",

""

],

"url": [

"\\.(bak|inc|old|mdb|sql|backup|java|class)$",

"jio"

],

"action": "deny"

}

2、我們需要設置管理后臺僅允許部分ip可以訪問,那么就在app_Mod中設置

{

"state": "on",

"action":["allow"],

"allow":["ip",["106.37.236.170","1.1.1.1"],"table"],

"hostname":[["101.200.122.200","127.0.0.1"],"table"],

"url":["/api/.*","jio"]

}

看著配置也比較容易理解,host是101.200.122.200或者127.0.0.1的,訪問的目錄是/api/.*的,僅允許allow中的2個IP。

3、CC攻擊防護

攻擊類型

1)、行為(GET、POST等):目前主要還是這兩種method攻擊為主,其他的基本沒有,因為比較互聯網上的web應用也都是這兩種居多;

2)、被攻擊的點(前端的緯度) a: 用戶可直接訪問的URL(搜索、重CPU、IO、數據庫的點);b:嵌入的URL(驗證碼、ajax接口等);c:面向非瀏覽器的接口(一些API、WEBservice等);d:基于特定web服務、語言等的特定攻擊(慢速攻擊、PHP-dos等)。

防護方法

1)網絡層:通過訪問ip的頻率、統計等使用閥值的方式進行頻率和次數的限制,黑名單方式;

2)網絡層+應用層:在后來的互聯網網絡下,有了CDN的加入,現在增加的網絡層的防護需要擴展,那么統計的IP將是在HTTP頭中的IP,仍然使用頻率、次數、黑名單的方式操作。

3)應用層:TAG驗證、SET COOKIE、URL跳轉、JS跳轉、驗證碼、頁面嵌套、強制靜態緩存等;防護是需要根據攻擊點進行分別防護的,如攻擊的是嵌入的url,我們就不能使用JS跳轉、302驗證碼等這樣的方法;在多次的CC防護實戰中,如使用url跳轉、setcookie;在新型的CC攻擊下,這些防護都已經失效了。瀏覽器是可以執行JS和flash的,這里我分享一些基于JS的防護算法,flash需要自己去寫(比js復雜一些),可以實現flash應用層的安全防護和防頁面抓取(開動你的大腦吧);

4)客戶端防護:使用JS進行前端的防護(瀏覽器識別、鼠標軌跡判斷、url有規則添加尾巴(args參數)、隨機延遲、鼠標鍵盤事件獲取等)其實這里非常復雜,如瀏覽器的識別 ie 支持?!-[1,]這個特殊JS,一些瀏覽器有自定義標簽等等;

5)服務端防護:url添加的尾巴(args參數)是服務器動態生成的token,而不是使用靜態的正則去匹配其合法性;

6)特定攻擊:該類特定攻擊,可以通過特征快速匹配出來(慢速攻擊、PHP5.3的http頭攻擊)。

目前已經有了一些應用層的防護都是基于js的(還得自己寫js),后續有時間會把驗證碼等加上,這個很實用。

誤報肯定是有的,使用時需要根據自己的業務進行調整。

動態配置規則

提供了相應的http接口來增刪相應的規則;方便規則的維護。

更多案例和配置示例請參考https://github.com/starjun/openstar。

由于本應用時為了解決當前公司的存在的問題,代碼質量、代碼實現可能存在不到位的地方,多多探討。感謝春哥、OpenResty社區、loveshell。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,321評論 6 543
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,559評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,442評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,835評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,581評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,922評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,931評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,096評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,639評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,374評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,591評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,104評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,789評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,196評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,524評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,322評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,554評論 2 379

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,826評論 18 139
  • http://192.168.136.131/sqlmap/mysql/get_int.php?id=1 當給sq...
    xuningbo閱讀 10,387評論 2 22
  • sqlmap用戶手冊 說明:本文為轉載,對原文中一些明顯的拼寫錯誤進行修正,并標注對自己有用的信息。 ======...
    wind_飄閱讀 2,077評論 0 5
  • 前言 WAF(Web Application Firewall),網站應用級入侵防御系統,通過執行一系列針對 HT...
    泡面辦公室閱讀 2,356評論 0 7
  • 我的姐姐最近剛生了二胎,寶寶很可愛,可是我總覺她閑在家里只帶孩子太浪費時間了,于是在我的逼迫下她開始做童裝。 ...
    愛狗的流浪貓閱讀 76評論 0 0