通过比较多种开源库和付费WAF服务,最终还是选择了:ModSecurity
理由
官方网站和相关资料链接
- 官方网站 https://www.modsecurity.org
- Modsecurity仓库 https://github.com/SpiderLabs/ModSecurity
- ModSecurity-nginx仓库 https://github.com/SpiderLabs/ModSecurity-nginx
- 规则仓库 https://github.com/coreruleset/coreruleset
- Nginx官方下载地址 http://nginx.org/en/download.html
准备环境
安装必要库
1
sudo apt-get install g++ flex bison curl doxygen libyajl-dev libgeoip-dev libtool dh-autoreconf libcurl4-gnutls-dev libxml2 libpcre++-dev libxml2-dev
下载库
- 下载ModSecurity库
1
git clone --depth 1 -b v3/master --single-branch https://github.com/SpiderLabs/ModSecurity
- 下载ModSecurity-ngin库
1
git clone --depth 1 https://github.com/SpiderLabs/ModSecurity-nginx.git
下载和已经安装好的nginx匹配的nginx源文件
地址:http://nginx.org/en/download.html
使用命令nginx -V 可以查看ngix的版本,务必要和已经安装的nginx保持一致,不然会出问题的。通过实践,nginx 1.10.3这样比较低的版本无法使用ModSercurity V3.X, 因此如果要nginx版本太低,后面是没有办法编译成功的。这是趟坑的结论。
1
2
3
4
5
6
7
8nginx -V
nginx version: nginx/1.10.3 (Ubuntu)
built with OpenSSL 1.0.2g 1 Mar 2016
TLS SNI support enabled
configure arguments: --with-cc-opt='-g -O2 -fPIE -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -fPIE -pie -Wl,-z,relro -Wl,-z,now' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-ipv6 --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_addition_module --with-http_dav_module --with-http_geoip_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module --with-http_v2_module --with-http_sub_module --with-http_xslt_module --with-stream --with-stream_ssl_module --with-mail --with-mail_ssl_module --with-threads
wget nginx-1.10.3 #下载对应的nginx注意保存好nginx的配置configure arguments
##安装ModSecurity需要的可选库(最好还是装上)
安装perl (可能是不必要的)
命名:
1
2
sudo apt-get install libperl-dev
LUA(安装5.3版本)
一定要安装liblua5.3-dev,不然检查配置的时候是无法检查到lua的。
1
2
apt-get install liblua5.3-0 liblua5.3-dev libreadline-dev libreadline6-dev libtinfo-dev libtool-bin
ssdeep 模糊哈希算法工具
ModSecurity利用其来计算是否有入侵,需要搭配指纹库使用。
下载最新版本(2020-11-23)
1
wget https://github.com/ssdeep-project/ssdeep/releases/download/release-2.14.1/ssdeep-2.14.1.tar.gz
解压
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25mv release-2.14.1.tar.gz ssdeep-release-2.14.1.tar.gz #这里主要是为了和其他下载的包区分,所以改个名字
tar -xzf ssdeep-release-2.14.1.tar.gz
cd ssdeep-release-2.14.1/
./configure #在这里会显示缺少的库,找到必须安装的,安装。
````
发现需要的文件实在太多了。。。先放弃了。如果实在要用到,再一一安装吧。。。。
# 编译ModSecurity核心库
安装文档:
https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual-%28v2.x%29#installation-for-nginx
1. 从github仓库克隆仓库到服务器
1. 预备
````shell
cd ModSecurity
git submodule init
git submodule update
./build.sh
./configure #如有可选依赖,可以先安装需要的库,再进行下一步。
make
make install #如果失败,使用sudo make install
编译nginx和ModSecurity-nginx模块
编译nginx模块
切换到nginx源码文件夹
如果nginx版本小于1.11.5,可能无法使用动态模块,或无法使用参数–with-compat1
./configure --add-module=/path/to/ModSecurity-nginx
编译nginx动态模块
1
./configure --add-dynamic-module=/path/to/ModSecurity-nginx --with-compat
注意:这里的参数要和前面已经保存下来的nginx参数合并,不要单独只执行这一条。
安装的时候,可能会缺少库,报以下错误:
1
./configure: error: the HTTP XSLT module requires the libxml2/libxslt
其他可能缺少的安装库(如果曾经安装过,就不会缺)
1
2sudo apt-get install libxml2 libxml2-dev libxslt-dev
sudo apt-get install libgd-dev当继续./configure而没有提示缺少库后,就可以开始编译nginx了。
1
make
安装nginx
这里分3种情况:
已经安装过一个低版本
没有安装过nginx,执行命令进行安装。
1
sudo make install
- 已经安装过符合要求的nginx
在这个情况下,不需要执行 “sudo make install”
尝试运行,可能会遇到一些问题。
1
sudo nginx
缺少文件夹,缺少PID,例如:
1
"/usr/share/nginx/logs/nginx.pid" failed (2: No such file or directory)
就去创建这个文件,或者去/etc/nginx.conf配置中去指定PID文件路径
没有设置正确的路径(在./configure里设置过日志路径,但是文件夹不存在或被删除了)
1
"/var/lib/nginx/body" failed (2: No such file or directory)
同样,可以在/etc/nginx/nginx.conf配置这些路径,也可以根据错误提示去创建文件夹。
1
sudo mkdir -p /var/lib/nginx/body
配置nginx自启动
在/etc/init.d 新建nginx文件,加入下面的脚本。
如果PATH路径不对,则需要自己修改和添加哦,一般都是不用改的。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
### BEGIN INIT INFO
# Provides: nginx
# Required-Start: $local_fs $remote_fs $network $syslog $named
# Required-Stop: $local_fs $remote_fs $network $syslog $named
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: starts the nginx web server
# Description: starts nginx using start-stop-daemon
### END INIT INFO
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/sbin/nginx
NAME=nginx
DESC=nginx
# Include nginx defaults if available
if [ -r /etc/default/nginx ]; then
. /etc/default/nginx
fi
STOP_SCHEDULE="${STOP_SCHEDULE:-QUIT/5/TERM/5/KILL/5}"
test -x $DAEMON || exit 0
. /lib/init/vars.sh
. /lib/lsb/init-functions
# Try to extract nginx pidfile
PID=$(cat /etc/nginx/nginx.conf | grep -Ev '^\s*#' | awk 'BEGIN { RS="[;{}]" } { if ($1 == "pid") print $2 }' | head -n1)
if [ -z "$PID" ]; then
PID=/run/nginx.pid
fi
if [ -n "$ULIMIT" ]; then
# Set ulimit if it is set in /etc/default/nginx
ulimit $ULIMIT
fi
start_nginx() {
# Start the daemon/service
#
# Returns:
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
start-stop-daemon --start --quiet --pidfile $PID --exec $DAEMON --test > /dev/null \
|| return 1
start-stop-daemon --start --quiet --pidfile $PID --exec $DAEMON -- \
$DAEMON_OPTS 2>/dev/null \
|| return 2
}
test_config() {
# Test the nginx configuration
$DAEMON -t $DAEMON_OPTS >/dev/null 2>&1
}
stop_nginx() {
# Stops the daemon/service
#
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
start-stop-daemon --stop --quiet --retry=$STOP_SCHEDULE --pidfile $PID --name $NAME
RETVAL="$?"
sleep 1
return "$RETVAL"
}
reload_nginx() {
# Function that sends a SIGHUP to the daemon/service
start-stop-daemon --stop --signal HUP --quiet --pidfile $PID --name $NAME
return 0
}
rotate_logs() {
# Rotate log files
start-stop-daemon --stop --signal USR1 --quiet --pidfile $PID --name $NAME
return 0
}
upgrade_nginx() {
# Online upgrade nginx executable
# http://nginx.org/en/docs/control.html
#
# Return
# 0 if nginx has been successfully upgraded
# 1 if nginx is not running
# 2 if the pid files were not created on time
# 3 if the old master could not be killed
if start-stop-daemon --stop --signal USR2 --quiet --pidfile $PID --name $NAME; then
# Wait for both old and new master to write their pid file
while [ ! -s "${PID}.oldbin" ] || [ ! -s "${PID}" ]; do
cnt=`expr $cnt + 1`
if [ $cnt -gt 10 ]; then
return 2
fi
sleep 1
done
# Everything is ready, gracefully stop the old master
if start-stop-daemon --stop --signal QUIT --quiet --pidfile "${PID}.oldbin" --name $NAME; then
return 0
else
return 3
fi
else
return 1
fi
}
case "$1" in
start)
log_daemon_msg "Starting $DESC" "$NAME"
start_nginx
case "$?" in
0|1) log_end_msg 0 ;;
2) log_end_msg 1 ;;
esac
;;
stop)
log_daemon_msg "Stopping $DESC" "$NAME"
stop_nginx
case "$?" in
0|1) log_end_msg 0 ;;
2) log_end_msg 1 ;;
esac
;;
restart)
log_daemon_msg "Restarting $DESC" "$NAME"
# Check configuration before stopping nginx
if ! test_config; then
log_end_msg 1 # Configuration error
exit $?
fi
stop_nginx
case "$?" in
0|1)
start_nginx
case "$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
reload|force-reload)
log_daemon_msg "Reloading $DESC configuration" "$NAME"
# Check configuration before stopping nginx
#
# This is not entirely correct since the on-disk nginx binary
# may differ from the in-memory one, but that's not common.
# We prefer to check the configuration and return an error
# to the administrator.
if ! test_config; then
log_end_msg 1 # Configuration error
exit $?
fi
reload_nginx
log_end_msg $?
;;
configtest|testconfig)
log_daemon_msg "Testing $DESC configuration"
test_config
log_end_msg $?
;;
status)
status_of_proc -p $PID "$DAEMON" "$NAME" && exit 0 || exit $?
;;
upgrade)
log_daemon_msg "Upgrading binary" "$NAME"
upgrade_nginx
log_end_msg $?
;;
rotate)
log_daemon_msg "Re-opening $DESC log files" "$NAME"
rotate_logs
log_end_msg $?
;;
*)
echo "Usage: $NAME {start|stop|restart|reload|force-reload|status|configtest|rotate|upgrade}" >&2
exit 3
;;
esac启动服务
- 手动启动服务
1
systemctl start nginx
- 将服务加入自启动
1
2
3
4
5
6
7
8
9
10
11
12
13sudo systemctl enable nginx
····
## 动态加载Modsecurity-nginx.so模块
如果是之前编译nginx的时候,./configure的参数,选择的是动态模块的方式加载Modescurity-nginx,则需要在nginx.conf文件增加该模块。
如果不是,则忽略。
编辑/etc/nginx/nginx.conf文件,加载到最外层:
````shell
worker_processes 1 #这句本来就有的 可能数字不一样,根据CPU数量来配置。
load_module "modules/ngx_http_modsecurity_module.so";
在nginx.conf配置Modsecurity
参考文档:https://github.com/SpiderLabs/ModSecurity-nginx,
编辑context:server,或各vhost的配置文件
创建modescurity文件夹,用于放置防火墙规则等相关配置文件,方便加载
1
sudo mkdir /etc/nginx/modsecurity
打开Modsecurity源码根目录,拷贝modsecurity.conf配置文件到上一步创建的文件夹。
1
2cd ~/download/ModSecurity/
sudo cp modsecurity.conf-recommended /etc/nginx/modsecurity/modsecurity.conf修改nginx配置文件,引入modsecurity
1
2
3
4
5
6
7#省略其他配置,这里只记录和modsecurity相关的设置
server {
modsecurity on;
location / {
modsecurity_rules_file /etc/nginx/modsecurity/modsecurity.conf;
}
}配置防火墙规则
coreruleset 规则
官方网站 https://coreruleset.org/installation/
规则仓库 https://github.com/coreruleset/coreruleset
安装引导 https://www.netnea.com/cms/nginx-tutorial-7_including-owasp-modsecurity-core-rule-set/
规则仓库包括收费的话,会有多种,但是不要开启太多规则,不然会降低效能。
详细的安装方法,请查看上面的官方网站
精炼步骤:
从官方网站下载稳定版本的规则
1
2
3wget https://github.com/coreruleset/coreruleset/archive/v3.3.0.tar.gz #下载
mv v3.3.0.tar.gz coreruleset_v3.3.0.tar.gz #改名方便辨别
tar -xzf coreruleset_v3.3.0.tar.gz #解压复制配置文件和规则到nginx的配置文件夹
进入刚刚下载的文件夹coreruleset_v3.3.0,进行复制
1
2sudo cp crs-setup.conf.example /etc/nginx/modsecurity/crs-setup.conf
sudo cp -r ./rules /etc/nginx/modsecurity/修改配置 /etc/nginx/modsecurity/modsecurity.conf
- 根据服务的需要,调整配置
1
2
3SecRuleEngine DetectionOnly #它只会检测到所有的攻击,并根据攻击产生错误,但它不会在服务器上阻止任何东西
SecRuleEngine On #将在服务器上激活ModSecurity防火墙。它会检测并阻止该服务器上的任何恶意攻击。- 引入规则库
1
2Include /etc/nginx/modsecurity/crs-setup.conf
Include /etc/nginx/modsecurity/rules/*.conf
- 根据自己的需要编辑crs-setup.conf 配置防火墙规则
解决错误
重新启动nginx看看会发生什么,如果一切顺利,正常启动,那么就祝贺你,太走运了。
如果有错误,不用害怕,根据下面的,一步一步来解决。
去/var/log/nginx/error.log 查看出错信息(日志地址根据nginx.conf设置来,你的不一定是这个):
错误1: Failed to locate the unicode map file
1
2020/11/24 18:00:36 [emerg] 3015#3015: "modsecurity_rules_file" directive Rules error. File: /etc/nginx/modsecurity/modsecurity.conf. Line: 236. Column: 17. Failed to locate the unicode map file from: unicode.mapping Looking at: 'unicode.mapping', 'unicode.mapping', '/etc/nginx/modsecurity/unicode.mapping', '/etc/nginx/modsecurity/unicode.mapping'. in /etc/nginx/conf.d/dev2.ddkids.com.conf:13
解决方法:
在modesecurity源码文件夹将 unicode.mapping 复制到/nginx/modesecurity,问题得到解决。
编写简单脚本,测试是否生效。
在 /etc/nginx/modsecurity/ crs-setup.conf 找到 [Anti-Automation / DoS Protection]一节,
打开下面的动作,测试是否能阻止DoS攻击,被阻止会返回403错误给访问来源。1
2
3
4
5
6
7
8
9SecAction \
"id:900700,\
phase:1,\
nolog,\
pass,\
t:none,\
setvar:'tx.dos_burst_time_slice=60',\
setvar:'tx.dos_counter_threshold=100',\
setvar:'tx.dos_block_timeout=120'"注入式攻击测试
网页打开下面的地址,如果看到403错误,就代表生效了。
1
2
3
4
5
6
7
8
9
10http://dev2.ddkids.com/?q=%3Cscript%3E%20alert(1)%3C/script%3E
````
## 日志查看
日常被阻挡的4xx,5xx请求都会被记录在:
````shell
/var/log/modsec_audit.log可以通过编写脚本,定时将数据保存到数据库,或另存到本地。如果要合规的话,应该需要让日志方便可查吧?
日志文件会很大,为了合规必须开启,但是最多保留15-30天的数据。如果开启,则必须编写脚本定时处理。
高级日志分析
ModSecurity日志数据格式: https://github.com/SpiderLabs/ModSecurity/wiki/ModSecurity-2-Data-Formats
自动化存储和分析
可以使用其他自动化工具来做可视化分析
使用扫描漏洞工具来测试
- 工具: Nikto2 基于WEB信息漏洞扫描
WebScarab 网络爬虫:抓取目标网站
NoSQLMap 代码注入攻击测试
要使用稳定版,不要使用master版本,但是可能是自己不会用,没有攻击出什么东西。