WAF簡介
什么是WAF
Web應用防護系統(也稱:網站應用級入侵防御系統 。英文:Web Application Firewall,簡稱: WAF)。利用國際上公認的一種說法:Web應用 防火牆 是通過執行一系列針對HTTP/HTTPS的 安全策略 來專門為Web應用提供保護的一款產品。
WAF的功能
支持IP白名單和黑名單功能,直接將黑名單的IP訪問拒絕。
支持URL白名單,將不需要過濾的URL進行定義。
支持User-Agent的過濾,匹配自定義規則中的條目,然后進行處理(返回403)。
支持CC攻擊防護,單個URL指定時間的訪問次數,超過設定值,直接返回403。
支持Cookie過濾,匹配自定義規則中的條目,然后進行處理(返回403)。
支持URL過濾,匹配自定義規則中的條目,如果用戶請求的URL包含這些,返回403。
支持URL參數過濾,原理同上。
支持日志記錄,將所有拒絕的操作,記錄到日志中去
WAF的特點
1、異常檢測協議
Web應用防火牆會對HTTP的請求進行異常檢測,拒絕不符合HTTP標准的請求。並且,它也可以只允許HTTP協議的部分選項通過,從而減少攻擊的影響范圍。甚至,一些Web應用防火牆還可以嚴格限定HTTP協議中那些過於松散或未被完全制定的選項。
2、增強的輸入驗證
增強輸入驗證,可以有效防止網頁篡改、信息泄露、木馬植入等惡意網絡入侵行為。從而減小Web服務器被攻擊的可能性。
3、及時補丁
修補Web安全漏洞,是Web應用開發者最頭痛的問題,沒人會知道下一秒有什么樣的漏洞出現,會為Web應用帶來什么樣的危害。WAF可以為我們做這項工作了——只要有全面的漏洞信息WAF能在不到一個小時的時間內屏蔽掉這個漏洞。當然,這種屏蔽掉漏洞的方式不是非常完美的,並且沒有安裝對應的補丁本身就是一種安全威脅,但我們在沒有選擇的情況下,任何保護措施都比沒有保護措施更好。
4、基於規則的保護和基於異常的保護
基於規則的保護可以提供各種Web應用的安全規則,WAF生產商會維護這個規則庫,並時時為其更新。用戶可以按照這些規則對應用進行全方面檢測。還有的產品可以基於合法應用數據建立模型,並以此為依據判斷應用數據的異常。但這需要對用戶企業的應用具有十分透徹的了解才可能做到,可現實中這是十分困難的一件事情。
5、狀態管理
WAF能夠判斷用戶是否是第一次訪問並且將請求重定向到默認登錄頁面並且記錄事件。通過檢測用戶的整個操作行為我們可以更容易識別攻擊。狀態管理模式還能檢測出異常事件(比如登陸失敗),並且在達到極限值時進行處理。這對暴力攻擊的識別和響應是十分有利的。
6、其他防護技術
WAF還有一些安全增強的功能,可以用來解決WEB程序員過分信任輸入數據帶來的問題。比如:隱藏表單域保護、抗入侵規避技術、響應監視和信息泄露保護。
7、WAF相對於網絡防火牆的區別
網絡防火牆作為訪問控制設備,主要工作在OSI模型三、四層,基於IP報文進行檢測。只是對端口做限制,對TCP協議做封堵。其產品設計無需理解HTTP會話,也就決定了無法理解Web應用程序語言如HTML、SQL語言。因此,它不可能對HTTP通訊進行輸入驗證或攻擊規則分析。針對Web網站的惡意攻擊絕大部分都將封裝為HTTP請求,從80或443端口順利通過防火牆檢測。
一些定位比較綜合、提供豐富功能的防火牆,也具備一定程度的應用層防御能力,如能根據TCP會話異常性及攻擊特征阻止網絡層的攻擊,通過IP分拆和組合也能判斷是否有攻擊隱藏在多個數據包中,但從根本上說他仍然無法理解HTTP會話,難以應對如SQL注入、跨站腳本、cookie竊取、網頁篡改等應用層攻擊。
web應用防火牆能在應用層理解分析HTTP會話,因此能有效的防止各類應用層攻擊,同時他向下兼容,具備網絡防火牆的功能。
部署WAF
1、WAF實現規划
分析步驟如下:解析HTTP請求==》匹配規則==》防御動作==》記錄日志
具體實現如下:1、解析http請求:協議解析模塊 2.、匹配規則:規則檢測模塊,匹配規則庫 3、防御動作:return 403 或者跳轉到自定義界面 4、日志記錄:記錄到elk中,畫出餅圖,建議使用json格式
2、基於lua模塊部署nginx
至於nginx的安裝部署請參考:https://www.cnblogs.com/goser/articles/7550582.html,本文只做nginx基於lua模塊的編譯安裝
下載當前最新的lua及時編譯器luajit和nginx開發工具NDK(ngx_devel_kit),以及lua模塊lua-nginx-module
[root@linux-node2 ~]# cd /tools/ [root@linux-node2 tools]# wget http://luajit.org/download/LuaJIT-2.0.5.tar.gz [root@linux-node2 tools]# wget https://github.com/simplresty/ngx_devel_kit/archive/v0.3.0.tar.gz [root@linux-node2 tools]# wget https://github.com/openresty/lua-nginx-module/archive/v0.10.10.tar.gz [root@linux-node2 tools]# ll -rw-r--r-- 1 root root 849845 Aug 27 11:28 LuaJIT-2.0.5.tar.gz -rw-r--r-- 1 root root 611973 Aug 27 13:29 lua-nginx-module-0.10.10.tar.gz -rw-r--r-- 1 root root 66455 Aug 27 11:40 ngx_devel_kit-0.3.0.tar.gz
安裝LuaJIT
[root@linux-node2 tools]# tar xf LuaJIT-2.0.5.tar.gz [root@linux-node2 tools]# cd LuaJIT-2.0.5 [root@linux-node2 LuaJIT-2.0.5]# make && make install
解壓NDK和lua-nginx-module,並將解壓包放到nginx部署路徑下
[root@linux-node2 tools]# tar xf ngx_devel_kit-0.3.0.tar.gz [root@linux-node2 tools]# tar xf lua-nginx-module-0.10.10.tar.gz #創建存放NDK和lua模塊的路徑,將這些模塊放到這個路徑下 mkdir -p /application/nginx/extra/modules [root@linux-node2 tools]# cp -r ngx_devel_kit-0.3.0 /application/nginx/extra/modules/ngx_devel_kit [root@linux-node2 tools]# cp -r lua-nginx-module-0.10.10 /application/nginx/extra/modules/lua-nginx-module
創建luajit環境變量
[root@linux-node2 LuaJIT-2.0.5]# export LUAJIT_LIB=/usr/local/lib [root@linux-node2 LuaJIT-2.0.5]# export LUAJIT_INC=/usr/local/include/luajit-2.0
重新編譯nginx,將lua模塊添加進去
[root@linux-node2 tools]# cd nginx-1.12.2 [root@linux-node2 nginx-1.12.2]# ./configure --prefix=/application/nginx-1.12.2 --user=www --group=www --with-http_stub_status_module --with-http_ssl_module --add-module=/application/nginx/extra/modules/ngx_devel_kit/ --add-module=/application/nginx/extra/modules/lua-nginx-module/ --with-file-aio --with-http_dav_module #停止nginx服務,重新部署nginx [root@linux-node2 nginx-1.12.2]# /application/nginx/sbin/nginx -s stop [root@linux-node2 nginx-1.12.2]# make -j2 && make install # -j2表示同時使用兩個任務
檢查nginx語法報語法錯誤,解決如下:
[root@linux-node2 ~]# /application/nginx/sbin/nginx -t /application/nginx/sbin/nginx: error while loading shared libraries: libluajit-5.1.so.2: cannot open shared object file: No such file or directory #上面報錯 ,說明nginx沒有加載到lua庫,調整lua庫文件地址 [root@linux-node2 ~]# ln -s /usr/local/lib/libluajit-5.1.so.2 /lib64/libluajit-5.1.so.2 #啟動nginx服務 [root@linux-node2 ~]# /application/nginx/sbin/nginx
安裝完畢后,下面可以測試安裝了,修改nginx.conf 增加第一個配置
#部分代碼修改如下,在www.conf配置文件中添加如下location段 [root@linux-node2 conf]# vim extra/www.conf location /hello { default_type 'text/plain'; content_by_lua 'ngx.say("hello,lua,welcome!!!")'; } #重載nginx使配置生效 [root@linux-node2 conf]# /application/nginx/sbin/nginx -t [root@linux-node2 conf]# /application/nginx/sbin/nginx -s reload
使用瀏覽器打開http://192.168.80.172/hello檢查lua模塊是否加載
部署基於lua的waf應用:這里使用開源的waf項目https://github.com/loveshell/ngx_lua_waf
[root@linux-node3 ~]# git clone https://github.com/loveshell/ngx_lua_waf.git #將waf規則庫放到ngixn的配置文件路徑下 [root@linux-node3 ~]# mv ngx_lua_waf /application/nginx/conf/waf [root@linux-node3 ~]# cd /application/nginx/conf/waf/ #修改waf的配置文件,修改規則庫規則的對應路徑並設置日志記錄位置 [root@linux-node3 waf]# vim config.lua RulePath = "/application/nginx/conf/waf/wafconf/" attacklog = "on" logdir = "/tmp/" UrlDeny="on" Redirect="on" CookieMatch="on" postMatch="on" whiteModule="on" black_fileExt={"php","jsp"} ipWhitelist={"127.0.0.1"} ipBlocklist={"1.0.0.1"} CCDeny="on" CCrate="30/60" html=[[ <html xmlns="http://www.w3.org/1999/xhtml"><head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>網站防火牆</title> <style> p { line-height:20px; } ul{ list-style-type:none;} li{ list-style-type:none;} </style> </head> <body style=" padding:0; margin:0; font:14px/1.5 Microsoft Yahei, 宋體,sans-serif; color:#555;"> <div style="margin: 0 auto; width:1000px; padding-top:70px; overflow:hidden;"> <div style="width:600px; float:left;"> <div style=" height:40px; line-height:40px; color:#fff; font-size:16px; overflow:hidden; background:#6bb3f6; padding-left:20px;">網站防火牆 </div> <div style="border:1px dashed #cdcece; border-top:none; font-size:14px; background:#fff; color:#555; line-height:24px; height:220px; padding:20px 20px 0 20px; overflow-y:auto;background:#f3f7f9;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600; color:#fc4f03;">您的請求帶有不合法參數,已被網站管理員設置攔截!</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">可能原因:您提交的內容包含危險的攻擊請求</p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;">如何解決:</p> <ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1)檢查提交內容;</li> <li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2)如網站托管,請聯系空間提供商;</li> <li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3)普通網站訪客,請聯系網站管理員;</li></ul> </div> </div> </div> </body></html> ]] #修改ngxin.conf配置文件,在http段中添加如下內容 [root@linux-node3 conf]# vim nginx.conf .... lua_shared_dict limit 10m; lua_package_path "/application/nginx/conf/waf/?.lua"; init_by_lua_file /application/nginx/conf/waf/init.lua; access_by_lua_file /application/nginx/conf/waf/waf.lua; .... #重載nginx服務 [root@linux-node3 conf]# /application/nginx/sbin/nginx -t [root@linux-node3 conf]# /application/nginx/sbin/nginx -s reload
測試waf配置是否生效,使用http://192.168.80.173/mysql.sql模擬sql注入操作。顯示效果如下:
對應的日志記錄如下:
[root@linux-node3 conf]# tail -f /tmp/www.goser.com_2018-08-31_sec.log 192.168.201.211 [2018-08-31 13:56:31] "GET www.goser.com/mysql.sql" "-" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36" "\.(bak|inc|old|mdb|sql|backup|java|class)$"
測試客戶端使用壓力測試工具對網站攻擊
[root@linux-node2 tools]# yum install httpd-tools -y [root@linux-node2 tools]# ab -c 50 -n 1000 http://192.168.80.173/ 。。。。 Concurrency Level: 50 Time taken for tests: 0.707 seconds Complete requests: 1000 Failed requests: 941 。。。。 #通過上面的ab測壓工具可以看到失敗了941次客戶端請求,這是由config.lua配置文件決定的 。。。。 CCDeny="on" CCrate="30/60" 。。。。
使用openresty部署WAF
我們都知道Nginx有很多的特性和好處,但是在Nginx上開發成了一個難題,Nginx模塊需要用C開發,而且必須符合一系列復雜的規則,最重要的用C開發模塊必須要熟悉Nginx的源代碼,使得開發者對其望而生畏。為了開發人員方便,所以接下來我們要介紹一種整合了Nginx和lua的框架,那就是OpenResty,它幫我們實現了可以用lua的規范開發,實現各種業務,並且幫我們弄清楚各個模塊的編譯順序。關於OpenResty,我想大家應該不再陌生,隨着系統架構的不斷升級、優化,OpenResty在被廣泛的應用。
Nginx 采用的是 master-worker 模型,一個 master 進程管理多個 worker 進程,基本的事件處理都是放在 woker 中,master 負責一些全局初始化,以及對 worker 的管理。在OpenResty中,每個 woker 使用一個 LuaVM,當請求被分配到 woker 時,將在這個 LuaVM 里創建一個 coroutine(協程)。協程之間數據隔離,每個協程具有獨立的全局變量_G。
ps. 協程和多線程下的線程類似:有自己的堆棧,自己的局部變量,有自己的指令指針,但是和其他協程程序共享全局變量等信息。線程和協程的主要不同在於:多處理器的情況下,概念上來說多線程是同時運行多個線程,而協程是通過代碼來完成協程的切換,任何時刻只有一個協程程序在運行。並且這個在運行的協程只有明確被要求掛起時才會被掛起。
首先我們選擇使用OpenResty,其是由Nginx核心加很多第三方模塊組成,其最大的亮點是默認集成了Lua開發環境,使得Nginx可以作為一個Web Server使用。
借助於Nginx的事件驅動模型和非阻塞IO,可以實現高性能的Web應用程序。
而且OpenResty提供了大量組件如Mysql、Redis、Memcached等等,使在Nginx上開發Web應用更方便更簡單。目前在京東如實時價格、秒殺、動態服務、單品頁、列表頁等都在使用Nginx+Lua架構,其他公司如淘寶、去哪兒網等。
下載openresty並編譯安裝openresty
[root@linux-node2 tools]# wget https://openresty.org/download/openresty-1.13.6.1.tar.gz [root@linux-node2 tools]# tar xf openresty-1.13.6.1.tar.gz [root@linux-node2 tools]# cd openresty-1.13.6.1 [root@linux-node2 openresty-1.13.6.1]# ./configure --prefix=/application/openresty-1.13.6.1 --with-luajit --with-pcre --with-pcre-jit --user=www --group=www --with-http_stub_status_module --with-http_ssl_module [root@linux-node2 openresty-1.13.6.1]# gmake && gmake install [root@linux-node2 openresty-1.13.6.1]# ln -s /application/openresty-1.13.6.1 /application/openresty #停止原生的nginx服務,啟動openresty中的nginx服務 [root@linux-node2 openresty-1.13.6.1]# /application/nginx/sbin/nginx -s stop [root@linux-node2 openresty-1.13.6.1]# /application/openresty/nginx/sbin/nginx -t [root@linux-node2 openresty-1.13.6.1]# /application/openresty/nginx/sbin/nginx
測試openresty安裝
#修改nginx.conf文件,添加如下location段 [root@linux-node2 tools]# cd /application/openresty/nginx/conf/ [root@linux-node2 conf]# vim nginx.conf location /hi { default_type text/html; content_by_lua_block{ ngx.say("hello openrastry!!!"); } } #重載openresty中的nginx服務 [root@linux-node2 conf]# /application/openresty/nginx/sbin/nginx -s reload
打開http://192.168.80.172/hi
基於openresty來部署WAF
#在github上克隆下代碼 [root@linux-node2 ~]# git clone https://github.com/unixhot/waf.git #將waf文件拷貝到openresty的nginx路徑下 [root@linux-node2 ~]# cp -r waf/waf/ /application/openresty/nginx/conf/ #修改waf中的config.lua文件,修改lua防火前規則路徑 [root@linux-node2 ~]# cd /application/openresty/nginx/conf/ [root@linux-node2 conf]# vim waf/config.lua --WAF config file,enable = "on",disable = "off" --waf status config_waf_enable = "on" --log dir config_log_dir = "/tmp/waf_logs" --rule setting config_rule_dir = "/application/openresty/nginx/conf/waf/rule-config" --enable/disable white url config_white_url_check = "on" --enable/disable white ip config_white_ip_check = "on" --enable/disable block ip config_black_ip_check = "on" --enable/disable url filtering config_url_check = "on" --enalbe/disable url args filtering config_url_args_check = "on" --enable/disable user agent filtering config_user_agent_check = "on" --enable/disable cookie deny filtering config_cookie_check = "on" --enable/disable cc filtering config_cc_check = "on" --cc rate the xxx of xxx seconds config_cc_rate = "30/60" --enable/disable post filtering config_post_check = "on" --config waf output redirect/html config_waf_output = "html" --if config_waf_output ,setting url config_waf_redirect_url = "https://www.cnblogs.com/goser" config_output_html=[[ <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Language" content="zh-cn" /> <title>網站防火牆</title> </head> <body> <h1 align="center"> 您的行為已違反本網站相關規定,注意操作規范。</h1> </body> </html> ]] #修改openresty中nginx的配置文件,在http段添加如下內容: [root@linux-node2 conf]# vim nginx.conf lua_shared_dict limit 50m; #防cc使用字典,大小50M lua_package_path "/application/openresty/nginx/conf/waf/?.lua"; init_by_lua_file "/application/openresty/nginx/conf/waf/init.lua"; access_by_lua_file "/application/openresty/nginx/conf/waf/access.lua"; #根據日志記錄位置,創建日志目錄並授予www用戶的權限 [root@linux-node2 conf]# mkdir /tmp/waf_logs [root@linux-node2 conf]# chown www.www /tmp/waf_logs/ #檢查nginx語法並重載nginx服務 [root@linux-node2 conf]# /application/openresty/nginx/sbin/nginx -t [root@linux-node2 conf]# /application/openresty/nginx/sbin/nginx -s reload
至於lua語言的編寫可以參考Nginx API for Lua :https://github.com/openresty/lua-nginx-module#nginx-api-for-lua
模擬sql注入即url攻擊
這時候日志顯示如下,記錄了UA,匹配規則,URL,客戶端類型,攻擊的類型,請求的數據
[root@linux-node2 conf]# tail -f /tmp/waf_logs/2018-08-30_waf.log {"local_time":"2018-08-30 11:52:23","client_ip":"192.168.80.253","rule_tag":"\\.(bak|inc|old|mdb|sql|backup|java|class|tgz|gz|tar|zip)$","attack_method":"Deny_URL","server_name":"192.168.80.172","req_url":"\/mysql.sql","req_data":"-","user_agent":"Mozilla\/5.0 (Windows NT 5.1) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/49.0.2623.112 Safari\/537.36"}
使用一台客戶端,使用ab壓測工具模擬防cc攻擊
#安裝ab測壓工具 [root@linux-node3 ~]# yum install httpd-tools -y [root@linux-node3 ~]# ab -c 50 -n 1000 http://192.168.80.172/ .... Concurrency Level: 50 Time taken for tests: 0.220 seconds Complete requests: 1000 Failed requests: 979 ...... #從上面可以看出失敗了979此請求,這是由config.lua配置文件配置決定的 [root@linux-node2 waf]# vim config.lua --cc rate the xxx of xxx seconds config_cc_rate = "30/60"
當然還可以模擬ip黑名單和模擬ip白名單,配置類似,只要在/application/openresty/nginx/conf/waf/rule-config/whiteip.rule或blackip.rule 規則文件添加白名單的ip或黑名單的ip
模擬URL參數檢測: 瀏覽器輸入http://192.168.3.140/?id=select * from name where name="goser",顯示如下:
WAF上線注意事項
初期上線只記錄日志,不開啟WAF,防止誤殺
WAF規則管理使用saltstack工具
要知道並不是有了WAF就安全,安全在很大一部分是人為因素