1.1 參考loveshell的waf實現思路,再此感謝下面其中一部分是轉載php
1.2 WAF的功能html
支持IP白名單和黑名單功能,直接將黑名單的IP訪問拒絕。
支持URL白名單,將不須要過濾的URL進行定義。
支持User-Agent的過濾,匹配自定義規則中的條目,而後進行處理(返回403)。
支持CC攻擊防禦,單個URL指定時間的訪問次數,超過設定值,直接返回403。
支持Cookie過濾,匹配自定義規則中的條目,而後進行處理(返回403)。
支持URL過濾,匹配自定義規則中的條目,若是用戶請求的URL包含這些,返回403。
支持URL參數過濾,原理同上。
支持日誌記錄,將全部拒絕的操做,記錄到日誌中去
1.3 WAF的特色java
異常檢測協議
Web應用防火牆會對HTTP的請求進行異常檢測,拒毫不符合HTTP標準的請求。而且,它也能夠只容許HTTP協議的部分選項經過,從而減小攻擊的影響範圍。甚至,一些Web應用防火牆還能夠嚴格限定HTTP協議中那些過於鬆散或未被徹底制定的選項。node
加強的輸入驗證
加強輸入驗證,能夠有效防止網頁篡改、信息泄露、木馬植入等惡意網絡入侵行爲。從而減少Web服務器被攻擊的可能性。
及時補丁
修補Web安全漏洞,是Web應用開發者最頭痛的問題,沒人會知道下一秒有什麼樣的漏洞出現,會爲Web應用帶來什麼樣的危害。WAF能夠爲咱們作這項工做了——只要有全面的漏洞信息WAF能在不到一個小時的時間內屏蔽掉這個漏洞。固然,這種屏蔽掉漏洞的方式不是很是完美的,而且沒有安裝對應的補丁自己就是一種安全威脅,但咱們在沒有選擇的狀況下,任何保護措施都比沒有保護措施更好。
基於規則的保護和基於異常的保護
基於規則的保護能夠提供各類Web應用的安全規則,WAF生產商會維護這個規則庫,並時時爲其更新。用戶能夠按照這些規則對應用進行全方面檢測。還有的產品能夠基於合法應用數據創建模型,並以此爲依據判斷應用數據的異常。但這須要對用戶企業的應用具備十分透徹的瞭解纔可能作到,可現實中這是十分困難的一件事情。
狀態管理
WAF可以判斷用戶是不是第一次訪問而且將請求重定向到默認登陸頁面而且記錄事件。經過檢測用戶的整個操做行爲咱們能夠更容易識別攻擊。狀態管理模式還能檢測出異常事件(好比登錄失敗),而且在達到極限值時進行處理。這對暴力攻擊的識別和響應是十分有利的。
其餘防禦技術
WAF還有一些安全加強的功能,能夠用來解決WEB程序員過度信任輸入數據帶來的問題。好比:隱藏表單域保護、抗入侵規避技術、響應監視和信息泄露保護。
1.3WAF與網絡防火牆的區別nginx
網絡防火牆做爲訪問控制設備,主要工做在OSI模型3、四層,基於IP報文進行檢測。只是對端口作限制,對TCP協議作封堵。其產品設計無需理解HTTP會話,也就決定了沒法理解Web應用程序語言如HTML、SQL語言。所以,它不可能對HTTP通信進行輸入驗證或攻擊規則分析。針對Web網站的惡意攻擊絕大部分都將封裝爲HTTP請求,從80或443端口順利經過防火牆檢測。
一些定位比較綜合、提供豐富功能的防火牆,也具有必定程度的應用層防護能力,如能根據TCP會話異常性及攻擊特徵阻止網絡層的攻擊,經過IP分拆和組合也能判斷是否有攻擊隱藏在多個數據包中,但從根本上說他仍然沒法理解HTTP會話,難以應對如SQL注入、跨站腳本、cookie竊取、網頁篡改等應用層攻擊。
web應用防火牆能在應用層理解分析HTTP會話,所以能有效的防止各種應用層攻擊,同時他向下兼容,具有網絡防火牆的功能。c++
2、使用nginx配置簡單實現403和404
2.1 小試身手之rerurn 403git
修改nginx配置文件在server中加入如下內容程序員
set $block_user_agent 0;
if ($http_user_agent ~ "Wget|AgentBench"){ # 注意if 和(之間要有空格,不然會報錯
set $block_user_agent 1;
}github
if ($block_user_agent = 1){
return 403;
}
經過其餘機器去wget,結果以下web
[root@mini1 ~]# wget http://192.168.3.140
--2017-05-05 14:14:53-- http://192.168.3.140/
Connecting to 192.168.3.140:80... connected.
HTTP request sent, awaiting response... 403 Forbidden
2017-05-05 14:14:53 ERROR 403: Forbidden.
2.2小試身手之rerurn 404
在nginx配置文件中加入以下內容,讓訪問sql|bak|zip|tgz|tar.gz的請求返回404
location ~* "\.(sql|bak|zip|tgz|tar.gz)$" {
return 404;
}
NGINX下如何自定義404頁面:
1.建立本身的404.html頁面
2.更改nginx.conf在http定義區域加入: fastcgi_intercept_errors on;
3.更改nginx.conf
中在server 區域加入: error_page 404 /404.html 或者 error_page 404 = http://www.xxx.com/404.html
4.更改後重啓nginx,,測試nginx.conf正確性: /user/local/nginx/sbin/nginx –t
在網站根目錄下放一個.sql
經過瀏覽器訪問結果以下,404已生效
3、深刻實現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能夠參考
安裝依賴包
yum install -y gcc gcc-c++ openssl-devel
環境準備 [root@nginx-lua ~]# cd /usr/local/src 首先,如今Nginx安裝必備的Nginx和PCRE軟件包。
[root@nginx-lua src]# wget http://nginx.org/download/nginx-1.9.4.tar.gz
[root@nginx-lua src]# wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.37.tar.gz
其次,下載當前最新的luajit和ngx_devel_kit (NDK),以及lua-nginx-module
[root@nginx-lua src]# wget http://luajit.org/download/LuaJIT-2.0.4.tar.gz
[root@nginx-lua src]# wget https://github.com/simpl/ngx_devel_kit/archive/v0.2.19.tar.gz
[root@nginx-lua src]# wget https://github.com/openresty/lua-nginx-module/archive/v0.9.16.tar.gz
最後,建立Nginx運行的普通用戶 [root@nginx-lua src]# useradd -s /sbin/nologin -M www
解壓NDK和lua-nginx-module
[root@node1 src]# tar zxvf v0.2.19.tar.gz # 解壓後爲ngx_devel_kit-0.2.19
[root@node1 src]# tar -zxvf v0.9.16.tar.gz # 解壓後爲lua-nginx-module-0.9.16
[root@node1 src]# tar zxf pcre-8.37.tar.gz
安裝LuaJIT Luajit是Lua即時編譯器
[root@node1 src]# tar zxvf LuaJIT-2.0.4.tar.gz
[root@node1 src]# cd LuaJIT-2.0.4
[root@node1 LuaJIT-2.0.4]# make && make install
安裝Nginx並加載模塊(說明該編譯方式只能適配nginx1.9.4版本的nginx,1.10和1.12等沒法適配)
[root@node1 nginx-1.9.4]# tar zxf nginx-1.9.4.tar.gz
[root@node1 src]# cd cd nginx-1.9.4
[root@node1 nginx-1.9.4]# export LUAJIT_LIB=/usr/local/lib
[root@node1 nginx-1.9.4]# export LUAJIT_INC=/usr/local/include/luajit-2.0
[root@node1 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.37
[root@node1 nginx-1.9.4]# make -j2 && make install # -j2表示同時使用兩個任務
[root@openstack-compute-node5 ~]# 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,heihei")';
}
[root@node1 nginx]# /usr/local/nginx-1.9.4/sbin/nginx –t
[root@node1 nginx]# /usr/local/nginx-1.9.4/sbin/nginx
如下本身使用ubuntu14.04部署:
3.2.3 Openresty部署
安裝依賴包
# apt-cache serach readline
apt-get install libpcre-dev libpcrecpp0 libpcre3 //nginx要用它作正則引擎
apt-get install libreadline-dev libreadline6-dev libtinfo-dev
apt-get install openssl libssl-dev perl make build-essential curl //openssl作安全引擎
下載並編譯安裝openresty(ngx_openresty-1.9.3.2.tar.gz和nginx1.9.4兼容,其餘版本沒法和nginx1.9.4兼容)
[root@node1 html]# cd /usr/local/src/
[root@node1 src]# wget https://openresty.org/download/ngx_openresty-1.9.3.2.tar.gz
[root@node1 src]# tar -zxf ngx_openresty-1.9.3.2.tar.gz
[root@node1 src]# cd ngx_openresty-1.9.3.2
[root@node1 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
[root@node1 ngx_openresty-1.9.3.2]# make && make install
[root@node1 ngx_openresty-1.9.3.2]# ln -s /usr/local/openresty-1.9.3.2/ /usr/local/openresty
測試openresty安裝 //在 /usr/local/openresty/nginx/nginx.conf添加
location /hi {
default_type text/html;
content_by_lua_block{
ngx.say('hello openrastry')
}
}
測試並啓動openrestry下的nginx
[root@node1 ngx_openresty-1.9.3.2]# /usr/local/openresty/nginx/sbin/nginx -t //文本模式詳細信息
nginx: the configuration file /usr/local/openresty-1.9.3.2/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/openresty-1.9.3.2/nginx/conf/nginx.conf test is successful
[root@node1 ngx_openresty-1.9.3.2]# pkill nginx //殺死進程
[root@node1 ngx_openresty-1.9.3.2]# /usr/local/openresty/nginx/sbin/nginx/從新啓動
3.2.4WAF部署
在github上克隆下代碼
[root@node1 ~]# git clone https://github.com/unixhot/waf.git
Cloning into 'waf'...
remote: Counting objects: 75, done.
remote: Total 75 (delta 0), reused 0 (delta 0), pack-reused 75
Unpacking objects: 100% (75/75), done.
[root@node1 ~]# cp -a ./waf/waf /usr/local/openresty/nginx/conf/
修改Nginx的配置文件,加入(http字段)如下配置。注意路徑,同時WAF日誌默認存放在/tmp/日期_waf.log
[root@node1 ~]# vim /usr/local/openresty/nginx/conf/nginx.conf
#WAF
lua_shared_dict limit 50m; #防cc使用字典,大小50M
lua_package_path "/usr/local/openresty/nginx/conf/waf/?.lua"; //waf規則
init_by_lua_file "/usr/local/openresty/nginx/conf/waf/init.lua"; //初始化規則
access_by_lua_file "/usr/local/openresty/nginx/conf/waf/access.lua";
[root@node1 ~]# /usr/local/openresty/nginx/sbin/nginx -t
[root@node1 ~]# /usr/local/openresty/nginx/sbin/nginx -s reload //從新載入更新配置
根據日誌記錄位置,建立日誌目錄
[root@node1 ~]# mkdir /tmp/waf_logs
[root@node1 ~]# chown -R www.www /tmp/waf_logs //這裏要給此文件夾存放權限,能夠暫時使用777權限,原則上要使用nginx的用戶組
3.3學習模塊
3.3.1學習配置模塊
WAF上生產以前,建議不要直接上生產,而是先記錄日誌,不作任何動做。肯定WAF不產生誤殺
config.lua即WAF功能詳解
# pwd
# /usr/local/openresty/nginx/conf/waf
[root@node1 waf]# vim 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"> 您的行爲已違反本網站相關規定,注意操做規範。</h1>
</body>
</html>
]]
3.4 學習access.lua的配置
[root@node1 waf]# pwd
/usr/local/openresty/nginx/conf/waf
[root@node1 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,客戶端類型,攻擊的類型,請求的數據
[root@node1 waf]# tail -f /tmp/waf_logs/2017-05-05_waf.log
{"user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/57.0.2987.133 Safari\/537.36","rule_tag":"\\.(bak|inc|old|mdb|sql|backup|java|class|tgz|gz|tar|zip)$","req_url":"\/abc.sql","client_ip":"192.168.3.84","local_time":"2017-05-05 17:06:28","attack_method":"Deny_URL","req_data":"-","server_name":"localhost"}
{"user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/57.0.2987.133 Safari\/537.36","rule_tag":"\\.(bak|inc|old|mdb|sql|backup|java|class|tgz|gz|tar|zip)$","req_url":"\/abc.sql","client_ip":"192.168.3.84","local_time":"2017-05-05 17:06:29","attack_method":"Deny_URL","req_data":"-","server_name":"localhost"}
{"user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/57.0.2987.133 Safari\/537.36","rule_tag":"\\.(bak|inc|old|mdb|sql|backup|java|class|tgz|gz|tar|zip)$","req_url":"\/abc.sql","client_ip":"192.168.3.84","local_time":"2017-05-05 17:06:29","attack_method":"Deny_URL","req_data":"-","server_name":"localhost"}
3.5.2 使用ab壓測工具模擬防cc攻擊
[root@mini1 ~]# ab -n 1000 -c 50 http://192.168.3.140/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 192.168.3.140 (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests
Server Software: openresty/1.9.3.2
Server Hostname: 192.168.3.140
Server Port: 80
Document Path: /
Document Length: 612 bytes
Concurrency Level: 50
Time taken for tests: 0.674 seconds
Complete requests: 1000
Failed requests: 989
(Connect: 0, Receive: 0, Length: 989, Exceptions: 0)
Write errors: 0
Non-2xx responses: 989 # config.lua中設置的,60秒內只容許10個請求
Total transferred: 334731 bytes
HTML transferred: 178818 bytes
Requests per second: 1483.92 [#/sec] (mean)
Time per request: 33.695 [ms] (mean)
Time per request: 0.674 [ms] (mean, across all concurrent requests)
Transfer rate: 485.07 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 1 1.0 1 7
Processing: 4 32 3.7 32 38
Waiting: 2 32 3.8 32 38
Total: 11 33 3.0 33 41
Percentage of the requests served within a certain time (ms)
50% 33
66% 34
75% 34
80% 34
90% 35
95% 36
98% 37
99% 38
100% 41 (longest request)
3.5.3 模擬ip黑名單
將請求ip放入ip黑名單中
[root@node1 waf]# echo "192.168.3.84" >>/usr/local/openresty/nginx/conf/waf/rule-config/blackip.rule
顯示結果以下
3.5.4 模擬ip白名單
將請求ip放入ip白名單中,此時將不對此ip進行任何防禦措施,因此sql注入時應該返回404
[root@node1 waf]# echo "192.168.3.84" >> /usr/local/openresty/nginx/conf/waf/rule-config/whiteip.rule
顯示結果以下
3.5.5 模擬URL參數檢測
瀏覽器輸入http://192.168.3.140/?id=select * from name where name="jack"
顯示結果以下
詳細規定在arg.rule中有規定,對請求進行了規範
[root@node1 rule-config]# cat /usr/local/openresty/nginx/conf/waf/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)\=
既然這裏面安裝openresty,以前先要完全刪除nginx,由於openresty自帶nginx。
sudo apt-get
sudo apt-get autoremove
ps -ef |grep nginx
dpkg --get-selections|grep nginx /
sudo apt-get
ps -ef |grep nginx//看一下進程,還有就刪掉
這就完事了嗎?固然不是,你會發現當你以前安裝lnmp在Ubuntu時會有不少問題,記得及時查看錯誤日誌,發現問題
若是出現502錯誤,就是php-fpm.sock有問題
若是出現503錯誤,是nginx.conf有問題。
若是出現404問題,查看location ~ \.php$ {
root /data/web(這裏換成本身的主目錄);
還有server裏有沒有主目錄的聲明
若是出現一直提示:An error occurred.
PHP的PHP-FPM服務是啓動成功的,nginx也是啓動成功的,折騰了幾回,看nginx錯誤日誌,發現有權限錯誤~
查看php-fpm.conf文件中相關配置,得出解決辦法:
;listen.user = nobody
;listen.group = nobody
去掉前面的;號,而後將用戶和用戶組換成你的用戶和用戶組便可!,此時只是fpm修改了用戶組,但此時要清楚nginx也要修改爲相同的用戶組
vi /usr/local/nginx/conf/nginx.conf
開頭有一個
#user nobody;
把井號刪掉,nobody改成 用戶名 [空格] 用戶組,例如
user nginx web;
即以web組的nginx用戶來運行nginx.
修改完之後
/usr/local/nginx/sbin/nginx -s reload
重啓nginx
在本身測試攻防時,常常會出現文件上傳限制問題致使waf沒有攔截請求就報錯,雖然屬於開發問題,解決方法:
着報錯緣由是nginx不容許上傳配置過大的文件,那麼件把nginx的上傳大小配置調高就好。
二、修改後,測試nginx配置是否正確
- /usr/local/nginx/sbin/nginx -t
三、測試配置正確後,重啓nginx使配置生效
- /etc/init.d/nginx restart
注意:要是以php運行的話,這個大小client_max_body_size要和php.ini中的以下值的最大值差很少或者稍大,這樣就不會由於提交數據大小不一致出現錯誤。
- post_max_size = 2M
- upload_max_filesize = 2M
當中的2m修改爲你須要的容許文件大小。把當中的2m修改爲你第一步設置的大小。
4、防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地址https://github.com/centos-bz/HttpGuard
5、WAF上線