使用Nginx+Lua實現waf
軟件包需求:
1 、Nginx兼容性【最后測試到1.13.6】
wget http://nginx.org/download/nginx-1.13.6.tar.gz
2 、PCRE為Nginx編譯安裝關系的依賴
wget https://jaist.dl.sourceforge.net/project/pcre/pcre/8.42/pcre-8.42.tar.gz
3 、下載luajit解釋器和ngx_devel_kit以及lua-nginx-module模塊
wget http://luajit.org/download/LuaJIT-2.0.5.tar.gz wget https://github.com/simplresty/ngx_devel_kit/archive/v0.3.0.tar.gz wget https://github.com/openresty/lua-nginx-module/archive/v0.10.13.tar.gz
4 、文件解壓:
tar xf nginx-1.13.6.tar.gz pcre-8.42.tar.gz LuaJIT-2.0.5.tar.gz v0.3.0.tar.gz v0.10.13.tar.gz
5 、安裝LuaJIT Luajit是Lua即時編譯器
cd LuaJIT-2.0.5/make && make install
6 、添加環境變量
export LUAJIT_LIB=/usr/local/lib export LUAJIT_INC=/usr/local/include/luajit-2.0
7 、安裝Nginx並加載模塊【注意目錄位置以及版本】
- --prefix=/usr/local/nginx-1.13.6 # nginx 安裝目錄
- --with-pcre=/usr/local/src/pcre-8.42 # pcre 所在目錄
- --add-module=../ngx_devel_kit-0.3.0/ # ngx_devel_kit 所在目錄
- --add-module=../lua-nginx-module-0.10.13/ # lua-nginx-module 所在目錄
- -j2 調用編譯CPU的核數
cd nginx-1.13.6/./configure --user=www --group=www --prefix=/usr/local/nginx-1.13.6 --with-pcre=/usr/local/src/pcre-8.42 --with-http_stub_status_module --with-http_sub_module --with-http_gzip_static_module --without-mail_pop3_module --without-mail_imap_module --without-mail_smtp_module --add-module=../ngx_devel_kit-0.3.0/ --add-module=../lua-nginx-module-0.10.13/make -j2 && make install
8 、添加鏈接文件
ln -s /usr/local/nginx-1.13.6 /usr/local/nginx ln -s /usr/local/lib/libluajit-5.1.so.2 /lib64/libluajit-5.1.so.2 #一定創建此軟連接,否則報錯
應用配置
1 )調用lua測試,編輯Nginx.conf 添加/hello
vim /usr/local/nginx/conf/nginx.conf location /hello { default_type 'text/plain'; content_by_lua 'ngx.say("hello,lua")'; }
2 )語法檢查並啟動
/usr/local/nginx/sbin/nginx -t /usr/local/nginx/sbin/nginx curl 192.168.55.110/hello hello,lua 正常
WAF部署
1 )下載waf源碼:
cd /usr/local/nginx/conf/ git clone https://github.com/loveshell/ngx_lua_waf.git mv ngx_lua_waf/ waf
2 )文件注釋
config.lua # 配置文件 init.lua # 規則函數 waf.lua # 邏輯關系 # wafconf # 正則匹配關系目錄 wafconf/args # 里面的規則get參數進行過濾的 wafconf/url # 是只在get請求url過濾的規則 wafconf/post # 是只在post請求過濾的規則 wafconf/whitelist # 是白名單,里面的url匹配到不做過濾 wafconf/user-agent # 是對user-agent的過濾規則
3 )config.lua 注釋:
RulePath = "/usr/local/nginx/conf/waf/wafconf/" --規則存放目錄 attacklog = "off" --是否開啟攻擊信息記錄,需要配置logdir logdir = "/usr/local/nginx/logs/hack/" --log存儲目錄,該目錄需要用戶自己新建,切需要nginx用戶的可寫權限 UrlDeny="on" --是否攔截url訪問 Redirect="on" --是否攔截后重定向 CookieMatch = "on" --是否攔截cookie攻擊 postMatch = "on" --是否攔截post攻擊 whiteModule = "on" --是否開啟URL白名單 black_fileExt={"php","jsp"} --填寫不允許上傳文件后綴類型 ipWhitelist={"127.0.0.1"} --ip白名單,多個ip用逗號分隔 ipBlocklist={"1.0.0.1"} --ip黑名單,多個ip用逗號分隔 CCDeny="on" --是否開啟攔截cc攻擊(需要nginx.conf的http段增加lua_shared_dict limit 10m;) CCrate = "100/60" --設置cc攻擊頻率,單位為秒. --默認1分鍾同一個IP只能請求同一個地址100次 html=[[Please go away~~]] --警告內容,可在中括號內自定義 備注:不要亂動雙引號,區分大小寫
4 )修改Nginx配置文件引用WAF功能【http段加入】
lua_shared_dict limit 50m; lua_package_path "/usr/local/nginx/conf/waf/?.lua"; init_by_lua_file "/usr/local/nginx/conf/waf/init.lua"; access_by_lua_file "/usr/local/nginx/conf/waf/waf.lua";
5 )詳情:
cat nginx.conf http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; lua_shared_dict limit 50m; lua_package_path "/usr/local/nginx/conf/waf/?.lua"; init_by_lua_file "/usr/local/nginx/conf/waf/init.lua"; access_by_lua_file "/usr/local/nginx/conf/waf/waf.lua"; server { listen 80; server_name localhost; location / { root html; index index.html index.htm; } location /hello { default_type 'text/plain'; content_by_lua 'ngx.say("hello,lua")'; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } }
6 )創建日志目錄給予www用戶權限:
mkdir /usr/local/nginx/logs/hack/
chown www.www /usr/local/nginx/logs/hack/
7 )啟動Nginx 並測試:
/usr/local/nginx/sbin/nginx -t
/usr/local/nginx/sbin/nginx -s reload
8 )測試是否阻止請求:
http://192.168.55.110/hello?id=../etc/passwd
9 )通過ab模仿cc攻擊:
[root@nq waf]# ab -c 100 -n 1200 http://192.168.55.110/hello
其他
一個頁面版WAF--VeryNginx: https://github.com/alexazhou/VeryNginx
知識點:
#啟動服務 /opt/verynginx/openresty/nginx/sbin/nginx #停止服務 /opt/verynginx/openresty/nginx/sbin/nginx -s stop #重啟服務 /opt/verynginx/openresty/nginx/sbin/nginx -s reload web密碼配置: /opt/verynginx/verynginx/lua_script/VeryNginxConfig.lua Nginx 配置文件nginx.conf /opt/verynginx/openresty/nginx/conf/nginx.conf 規則配置: /opt/verynginx/verynginx/configs/config.json
#################################################################################################
一、了解WAF
1.1 什么是WAF
Web應用防護系統(也稱:網站應用級入侵防御系統 。英文:Web Application Firewall,簡稱: WAF)。利用國際上公認的一種說法:Web應用 防火牆 是通過執行一系列針對HTTP/HTTPS的 安全策略 來專門為Web應用提供保護的一款產品。
1.2 WAF的功能
- 支持IP白名單和黑名單功能,直接將黑名單的IP訪問拒絕。
- 支持URL白名單,將不需要過濾的URL進行定義。
- 支持User-Agent的過濾,匹配自定義規則中的條目,然后進行處理(返回403)。
- 支持CC攻擊防護,單個URL指定時間的訪問次數,超過設定值,直接返回403。
- 支持Cookie過濾,匹配自定義規則中的條目,然后進行處理(返回403)。
- 支持URL過濾,匹配自定義規則中的條目,如果用戶請求的URL包含這些,返回403。
- 支持URL參數過濾,原理同上。
- 支持日志記錄,將所有拒絕的操作,記錄到日志中去
1.3 WAF的特點
- 異常檢測協議
Web應用防火牆會對HTTP的請求進行異常檢測,拒絕不符合HTTP標准的請求。並且,它也可以只允許HTTP協議的部分選項通過,從而減少攻擊的影響范圍。甚至,一些Web應用防火牆還可以嚴格限定HTTP協議中那些過於松散或未被完全制定的選項。
- 增強的輸入驗證
增強輸入驗證,可以有效防止網頁篡改、信息泄露、木馬植入等惡意網絡入侵行為。從而減小Web服務器被攻擊的可能性。 - 及時補丁
修補Web安全漏洞,是Web應用開發者最頭痛的問題,沒人會知道下一秒有什么樣的漏洞出現,會為Web應用帶來什么樣的危害。WAF可以為我們做這項工作了——只要有全面的漏洞信息WAF能在不到一個小時的時間內屏蔽掉這個漏洞。當然,這種屏蔽掉漏洞的方式不是非常完美的,並且沒有安裝對應的補丁本身就是一種安全威脅,但我們在沒有選擇的情況下,任何保護措施都比沒有保護措施更好。 - 基於規則的保護和基於異常的保護
基於規則的保護可以提供各種Web應用的安全規則,WAF生產商會維護這個規則庫,並時時為其更新。用戶可以按照這些規則對應用進行全方面檢測。還有的產品可以基於合法應用數據建立模型,並以此為依據判斷應用數據的異常。但這需要對用戶企業的應用具有十分透徹的了解才可能做到,可現實中這是十分困難的一件事情。 - 狀態管理
WAF能夠判斷用戶是否是第一次訪問並且將請求重定向到默認登錄頁面並且記錄事件。通過檢測用戶的整個操作行為我們可以更容易識別攻擊。狀態管理模式還能檢測出異常事件(比如登陸失敗),並且在達到極限值時進行處理。這對暴力攻擊的識別和響應是十分有利的。 - 其他防護技術
WAF還有一些安全增強的功能,可以用來解決WEB程序員過分信任輸入數據帶來的問題。比如:隱藏表單域保護、抗入侵規避技術、響應監視和信息泄露保護。
1.3WAF與網絡防火牆的區別
網絡防火牆作為訪問控制設備,主要工作在OSI模型三、四層,基於IP報文進行檢測。只是對端口做限制,對TCP協議做封堵。其產品設計無需理解HTTP會話,也就決定了無法理解Web應用程序語言如HTML、SQL語言。因此,它不可能對HTTP通訊進行輸入驗證或攻擊規則分析。針對Web網站的惡意攻擊絕大部分都將封裝為HTTP請求,從80或443端口順利通過防火牆檢測。
一些定位比較綜合、提供豐富功能的防火牆,也具備一定程度的應用層防御能力,如能根據TCP會話異常性及攻擊特征阻止網絡層的攻擊,通過IP分拆和組合也能判斷是否有攻擊隱藏在多個數據包中,但從根本上說他仍然無法理解HTTP會話,難以應對如SQL注入、跨站腳本、cookie竊取、網頁篡改等應用層攻擊。
web應用防火牆能在應用層理解分析HTTP會話,因此能有效的防止各類應用層攻擊,同時他向下兼容,具備網絡防火牆的功能。
二、使用nginx配置簡單實現403和404
2.1 小試身手之rerurn 403
修改nginx配置文件在server中加入以下內容
set $block_user_agent 0; if( $http_user_agent ~"Wget|AgentBench"){ set $block_user_agent 1; } if($block_user_agent =1){ return403; }
通過其他機器去wget,結果如下
2.2小試身手之rerurn 404
在nginx配置文件中加入如下內容,讓訪問sql|bak|zip|tgz|tar.gz的請求返回404
location ~*"\.(sql|bak|zip|tgz|tar.gz)$"{ return404 }
在網站根目錄下放一個tar.gz
[root@iZ28t900vpcZ www]# tar zcvf abc.tar.gz wp-content/
通過瀏覽器訪問結果如下,404已生效
三、深入實現WAF
3.1 WAF實現規划
分析步驟如下:解析HTTP請求==》匹配規則==》防御動作==》記錄日志
具體實現如下:
- 解析http請求:協議解析模塊
- 匹配規則:規則檢測模塊,匹配規則庫
- 防御動作:return 403 或者跳轉到自定義界面
- 日志記錄:記錄到elk中,畫出餅圖,建議使用json格式
3.2安裝nginx+lua
由於nginx配置文件書寫不方便,並且實現白名單功能很復雜,nginx的白名單也不適用於CC攻擊,所以在這里使用nginx+lua來實現WAF,如果想使用lua,須在編譯nginx的時候配置上lua,或者結合OpenResty使用,此方法不需要編譯nginx時候指定lua
3.2.1 編譯nginx的時候加載lua
環境准備:Nginx安裝必備的Nginx和PCRE軟件包。
cd /usr/local/src wget http://nginx.org/download/nginx-1.9.4.tar.gz wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.37.tar.gz
其次,下載當前最新的luajit和ngx_devel_kit (NDK),以及春哥編寫的lua-nginx-module
wget http://luajit.org/download/LuaJIT-2.0..tar.gz wget https://github.com/simpl/ngx_devel_kit/archive/v0.2.19.tar.gz wget https://github.com/openresty/lua-nginx-module/archive/v0.9.16.tar.gz
最后,創建Nginx運行的普通用戶
useradd -s /sbin/nologin -M www
解壓NDK和lua-nginx-module
tar zxvf v0.2.19.tar.gz tar zxvf v0.9.16.tar.gz
安裝LuaJIT Luajit是Lua即時編譯器
tar zxvf LuaJIT-2.0.3.tar.gz cd LuaJIT-2.0.3make && make install
安裝Nginx並加載模塊
環境變量 export LUAJIT_LIB=/usr/local/lib export LUAJIT_INC=/usr/local/include/luajit-2.0
tar xf nginx-1.9.4.tar.gz
cd nginx-1.9.4
./configure --prefix=/usr/local/nginx --user=www --group=www --with-http_ssl_module --with-http_stub_status_module --with-file-aio --with-http_dav_module --add-module=../ngx_devel_kit-0.2.19/--add-module=../lua-nginx-module-0.9.16/--with-pcre=/usr/local/src/pcre-8.37make && make install ln -s /usr/local/lib/libluajit-5.1.so.2/lib64/libluajit-5.1.so.2 #一定創建此軟連接,否則報錯
安裝完畢后,下面可以測試安裝了,修改nginx.conf 增加第一個配置
location /hello { default_type 'text/plain'; content_by_lua 'ngx.say("hello,lua")'; }
/usr/local/nginx-1.9.4/sbin/nginx –t /usr/local/nginx-1.9.4/sbin/nginx
效果如下
3.2.3 Openresty部署
安裝依賴包
yum install -y readline-devel pcre-devel openssl-devel
下載並編譯安裝openresty
cd /usr/local/src wget https://openresty.org/download/ngx_openresty-1.9.3.2.tar.gz tar zxf ngx_openresty-1.9.3.2.tar.gz cd ngx_openresty-1.9.3.2./configure --prefix=/usr/local/openresty-1.9.3.2--with-luajit --with-http_stub_status_module --with-pcre --with-pcre-jit gmake && gmake install ln -s /usr/local/openresty-1.9.3.2//usr/local/openresty
測試openresty安裝
vim /usr/local/openresty/nginx/conf/nginx.conf
server { location /hello { default_type text/html; content_by_lua_block { ngx.say("HelloWorld") } } }
測試並啟動nginx
/usr/local/openresty/nginx/sbin/nginx -t
/usr/local/openresty/nginx/sbin/nginx
3.2.4WAF部署
在github上克隆下代碼
git clone https://github.com/unixhot/waf.git cp -a ./waf/waf /usr/local/openresty/nginx/conf/
修改Nginx的配置文件,加入(http字段)以下配置。注意路徑,同時WAF日志默認存放在/tmp/日期_waf.log
#WAF lua_shared_dict limit 50m; #防cc使用字典,大小50M lua_package_path "/usr/local/openresty/nginx/conf/waf/?.lua"; init_by_lua_file "/usr/local/openresty/nginx/conf/waf/init.lua"; access_by_lua_file "/usr/local/openresty/nginx/conf/waf/access.lua";
/usr/local/openresty/nginx/sbin/nginx –t /usr/local/openresty/nginx/sbin/nginx
根據日志記錄位置,創建日志目錄
mkdir /tmp/waf_logs
chown nginx.nginx /tmp/waf_logs
3.3學習模塊
3.3.1學習配置模塊
WAF上生產之前,建議不要直接上生產,而是先記錄日志,不做任何動作。確定WAF不產生誤殺
config.lua即WAF功能詳解
cd /usr/local/nginx/conf/waf cat 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 ="/usr/local/nginx/conf/waf/rule-config" #匹配規則縮放地址 --enable/disable white url config_white_url_check ="on" #是否開啟url檢測 --enable/disable white ip config_white_ip_check ="on" #是否開啟IP白名單檢測 --enable/disable block ip config_black_ip_check ="on" #是否開啟ip黑名單檢測 --enable/disable url filtering config_url_check ="on" #是否開啟url過濾 --enalbe/disable url args filtering config_url_args_check ="on" #是否開啟參數檢測 --enable/disable user agent filtering config_user_agent_check ="on" #是否開啟ua檢測 --enable/disable cookie deny filtering config_cookie_check ="on" #是否開啟cookie檢測 --enable/disable cc filtering config_cc_check ="on" #是否開啟防cc攻擊 --cc rate the xxx of xxx seconds config_cc_rate ="10/60" #允許一個ip60秒內只能訪問10此 --enable/disable post filtering config_post_check ="on" #是否開啟post檢測 --config waf output redirect/html config_waf_output ="html" #action一個html頁面,也可以選擇跳轉 --if config_waf_output ,setting url config_waf_redirect_url ="http://www.baidu.com" config_output_html=[[ #下面是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"># 您的行為已違反本網站相關規定,注意操作規范。詳情請聯微信公眾號:chuck-blog。 </body> </html> ]]
3.4 學習access.lua的配置
cd /usr/local/openresty/nginx/conf/waf cat access.lua require'init' function waf_main() if white_ip_check()then elseif black_ip_check()then elseif user_agent_attack_check()then elseif cc_attack_check()then elseif cookie_attack_check()then elseif white_url_check()then elseif url_attack_check()then elseif url_args_attack_check()then --elseif post_attack_check()then else return end end waf_main()
書寫書序:先檢查白名單,通過即不檢測;再檢查黑名單,不通過即拒絕,檢查UA,UA不通過即拒絕;檢查cookie;URL檢查;URL參數檢查,post檢查;
3.5 啟用WAF並測試
3.5.1模擬sql注入即url攻擊
顯示效果如下
日志顯示如下,記錄了UA,匹配規則,URL,客戶端類型,攻擊的類型,請求的數據
3.5.2 使用ab壓測工具模擬防cc攻擊
ab -c 100-n 100 192.168.4.10/index.php
This is ApacheBench,Version2.3<$Revision:1430300 $> Copyright1996AdamTwiss,ZeusTechnologyLtd, http://www.zeustech.net/ Licensed to TheApacheSoftwareFoundation, http://www.apache.org/ Benchmarking www.chuck-blog.com (be patient).....done ServerSoftware: openresty ServerHostname: 192.168.4.10 ServerPort:80 DocumentPath:/index.php DocumentLength:0 bytes ConcurrencyLevel:100 Time taken for tests:0.754 seconds Complete requests:10 Failed requests:90 #config.lua中設置的,60秒內只允許10個請求 Write errors:0 Non-2xx responses:90 Total transferred:22700 bytes HTML transferred:0 bytes Requests per second:132.65[#/sec](mean) Time per request:753.874[ms](mean) Time per request:7.539[ms](mean, across all concurrent requests) Transfer rate:29.41[Kbytes/sec] received ConnectionTimes(ms) min mean[+/-sd] median max Connect:236920.264105 Processing:32180144.5157629 Waiting:22179144.5156629 Total:56249152.4220702 Percentage of the requests served within a certain time (ms) 50%220 66%270 75%275 80%329 90%334 95%694 98%701 99%702 100%702(longest request) ``` ###3.5.3 模擬ip黑名單 將請求ip放入ip黑名單中
echo “1.202.193.133” >>/usr/local/openresty/nginx/conf/waf/rule-config/blackip.rule
顯示結果如下  ###3.5.4 模擬ip白名單 將請求ip放入ip白名單中,此時將不對此ip進行任何防護措施,所以sql注入時應該返回404
echo “1.202.193.133” >>/usr/local/openresty/nginx/conf/waf/rule-config/whiteip.rule
顯示結果如下  ###3.5.5 模擬URL參數檢測 瀏覽器輸入www.chuck-blog.com/?a=select*from table 顯示結果如下  詳細規定在arg.rule中有規定,對請求進行了規范 ```bash [root@iZ28t900vpcZ rule-config]# /usr/local/openresty/nginx/conf/waf/rule-config/cat 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)\= [root@iZ28t900vpcZ rule-config]# pwd /usr/local/openresty/nginx/conf/waf/rule-config
四、防cc攻擊利器之httpgrard
4.1 httpgrard介紹
HttpGuard是基於openresty,以lua腳本語言開發的防cc攻擊軟件。而openresty是集成了高性能web服務器Nginx,以及一系列的Nginx模塊,這其中最重要的,也是我們主要用到的nginx lua模塊。HttpGuard基於nginx lua開發,繼承了nginx高並發,高性能的特點,可以以非常小的性能損耗來防范大規模的cc攻擊。
4.2 httpgrard防cc特效
- 限制訪客在一定時間內的請求次數
- 向訪客發送302轉向響應頭來識別惡意用戶,並阻止其再次訪問
- 向訪客發送帶有跳轉功能的js代碼來識別惡意用戶,並阻止其再次訪問
- 向訪客發送cookie來識別惡意用戶,並阻止其再次訪問
- 支持向訪客發送帶有驗證碼的頁面,來進一步識別,以免誤傷
- 支持直接斷開惡意訪客的連接
- 支持結合iptables來阻止惡意訪客再次連接
- 支持白名單功能
- 支持根據統計特定端口的連接數來自動開啟或關閉防cc模式
詳見github地址,在后續的博文中會加入此功能
五、WAF上線
- 初期上線只記錄日志,不開啟WAF,防止誤殺
- WAF規則管理使用saltstack工具
- 要知道並不是有了WAF就安全,存在人為因素