Nginx + Lua实现WAF引用防火墙
- 常见恶意行为
- 常见的攻击手段
- 1. 实战
- 2.配置演示mysql防sql注入
- 访问攻击测试
- Nginx + Lua实现WAF引用防火墙
常见恶意行为
- 爬虫行为和恶意抓取,资源盗取
- 防护手段
- 基础防盗链功能不让恶意用户能够轻易的爬取到网站对外数据
-
access_module
-> 对后台,部分用户服务的数据提供IP防护 - 防护代码如下
# 防止恶意ab压测工具压测
server{
...
if ($http_user_agent ~* "Wget|ApacheBench"){
set $block_user_agent 1;
}
if ($block_user_agent = 1){
return 403;
}
}
常见的攻击手段
- 后台密码撞库,通过猜测密码字典不断对后台系统登陆性尝试,获取后台登录密码
- 防护手段
- 增加后台密码复杂度
- 使用
access_module
对后台提供IP防护 - 预警机制
- 文件上传漏洞,利用上传接口将恶意代码植入到服务器中,再通过url去访问执行代码
- 执行方式例如
xxx.com/1.jpg/2.php
- 解决办法如下:
location ^~ /upload {
root /soft/code/upload;
if ($request_filename ~* (.*)\.php){
return 403;
}
}
1. 实战
- 安装LNMP架构
# 192.168.1.17 上装的mysql5.7
rpm -ivh http://repo.mysql.com/yum/mysql-5.7-community/el/7/x86_64/mysql57-community-release-el7-10.noarch.rpm
yum install mysql-community-server
systemctl start mysqld.service
//查看初始密码
[root@nginx ~]# grep 'temporary password' /var/log/mysqld.log
2018-12-02T14:10:39.611954Z 1 [Note] A temporary password is generated for root@localhost: L#1e.qWawX>e
[root@nginx ~]# mysql -uroot -p
//添加远程连接用户w_root
mysql> grant all privileges on *.* to w_root@'192.168.1.%' identified by '!QAZ2wsx' with grant option;
mysql> flush privileges;
# 192.168.1.20上安装php php-fpm php-mysql
yum install -y php php-fpm php-mysql (后来测试发现php版本有些低,我就装成php7.2了)
# 或者直接将所有都装到一台机器上用 yum install -y php php-fpm php-mysql mariadb mariadb-server
# 测试连接mysql
[root@nginx_lua /soft/nginx/conf/conf.d]$ vim /soft/code/sql.php
<?php
$servername = '192.168.1.17';
$username = 'w_root';
$password = '!QAZ2wsx';
//creat connection
$conn = mysqli_connect($servername,$username,$password);
//test conn mysql
if(!$conn){
die("Connetion failed:".mysqli.connect_error());
}
echo "connection $servername mysql successed!";
?>
[root@kvm-node1 ~]# curl http://192.168.1.20/sql.php
connection 192.168.1.17 mysql successed!
[root@kvm-node1 ~]#
[root@nginx_lua /soft/nginx/conf/conf.d]$ vim phpserver.conf
server {
server_name 192.168.1.20;
root /soft/code;
index index.php index.html;
location ~* \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /soft/code/$fastcgi_script_name;
include fastcgi_params;
}
}
2.配置演示mysql防sql注入
mysql> create database info;
Query OK, 1 row affected (0.00 sec)
mysql> use info;
Database changed
mysql> create table user(id int(11),username varchar(64),password varchar(64),email varchar(64));
Query OK, 0 rows affected (0.08 sec)
mysql> desc user;
+----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| username | varchar(64) | YES | | NULL | |
| password | varchar(64) | YES | | NULL | |
| email | varchar(64) | YES | | NULL | |
+----------+-------------+------+-----+---------+-------+
4 rows in set (0.01 sec)
mysql> insert into user (id,username,password,email) values(1,'lss','123123','xxx@foxmail.com');
Query OK, 1 row affected (0.00 sec)
mysql> select * from user;
+------+----------+----------+-----------------+
| id | username | password | email |
+------+----------+----------+-----------------+
| 1 | lss | 123123 | xxx@foxmail.com |
+------+----------+----------+-----------------+
1 row in set (0.01 sec)
mysql> exit
Bye
- sql注入页面
[root@mysql-slave /soft/code]# vim login.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title> SQL 注入演示场景 </title>
</head>
<body>
<form action="login.php" method="get">
<table>
<tr>
<td> 用户:</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td> 密码:</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
<td><input type="submit" value="submit"></td>
<td><input type="reset" value="reset"></td>
</tr>
</table>
</form>
</body>
[root@mysql-slave /soft/code]# vim login.php
<?php
$conn = mysql_connect('192.168.1.17','root','') or die("数据库连接失败!");
mysql_select_db('info',$conn) or die("数据库不存在!");
$name=$_GET['username'];
$pwd=$_GET['password'];
$sql="select * from user where username='$name' and password='$pwd'";
mysql_query("set names 'utf8'");
$query=mysql_query($sql);
$arr=mysql_fetch_array($query);
if($arr){
echo "login successed!<br/>";
echo $arr[1];
echo $arr[3]."<br/><br />";
}else{
echo "login failed!";
}
echo "SQL: '$sql' ";
mysql_close($conn);
?>
- 报错:1055 - Expression #3 of SELECT list is not in GROUP BY clause and contains nonaggregated column ‘t1.tb1.id’ which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
Windows上安装的mysql在my.ini末尾加上下面这句话就可以了,Linux上就在my.conf上末尾添加
sql-mode="STRICT_ALL_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ZERO_DATE,NO_ZERO_IN_DATE,NO_AUTO_CREATE_USER"
访问攻击测试
- 正常访问
- sql注入
[root@mysql-slave /soft/code]# curl -I http://192.168.1.17/login.php?username=' or 0=0 #'&password=
[1] 127879
[root@mysql-slave /soft/code]# HTTP/1.1 200 OK
Server: nginx/1.14.2
Date: Sat, 22 Dec 2018 12:01:45 GMT
Content-Type: text/html
Connection: keep-alive
X-Powered-By: PHP/5.4.16
# MySQL中#后面都是注释内容
SQL: 'select * from user where username='' or 0=0 #'' and password='''
Nginx + Lua实现WAF引用防火墙
用途:
防止sql注入,本地包含,部分溢出,fuzzing测试,xss,SSRF等web攻击
防止svn/备份之类文件泄漏
防止ApacheBench之类压力测试工具的攻击
屏蔽常见的扫描黑客工具,扫描器
屏蔽异常的网络请求
屏蔽图片附件类目录php执行权限
防止webshell上传
推荐使用lujit2.1做lua支持
1. 开始部署
[root@mysql-slave /soft/src]# yum install -y git
[root@mysql-slave /soft/src]# git clone https://github.com/loveshell/ngx_lua_waf.git
[root@mysql-slave /soft/src]# cp -r ngx_lua_waf/ /soft/nginx/conf/waf
2. 在nginx.conf
的http
段添加
[root@mysql-slave /soft/nginx/conf/conf.d]# vim phpserver.conf
lua_package_path "/soft/nginx/conf/waf/?.lua";
lua_shared_dict limit 10m;
init_by_lua_file /soft/nginx/conf/waf/init.lua;
access_by_lua_file /soft/nginx/conf/waf/waf.lua;
3. 配置config.lua
里的waf规则目录(一般waf/conf/
目录下)
RulePath = "/soft/nginx/conf/waf/wafconf/"
[root@mysql-slave /soft/nginx/conf/waf]# vim config.lua
RulePath = "/soft/nginx/conf/waf/wafconf/" # 规则目录按实际更改
--规则存放目录
attacklog = "off"
--是否开启攻击信息记录,需要配置logdir
logdir = "/soft/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. 概述
过滤规则在wafconf下,可根据需求自行调整,每条规则需换行,或者用|分割
args里面的规则get参数进行过滤的
url是只在get请求url过滤的规则
post是只在post请求过滤的规则
whitelist是白名单,里面的url匹配到不做过滤
user-agent是对user-agent的过滤规则
默认开启了get和post过滤,需要开启cookie过滤的,编辑waf.lua取消部分--注释即可
日志文件名称格式如下:虚拟主机名_sec.log
5. 添加自定义规则
[root@mysql-slave /soft/nginx/conf/waf/wafconf]# vim post
\sor\s+ # 匹配 空格or空格...
...
- 可防止cc攻击
# 压测一把,在浏览器上访问就503了
ab -n 60000 -c 60 http://192.168.1.17/login.html
[root@kvm-node1 ~]# ab -n 200 -c 20 http://192.168.1.17/login.html
[root@mysql-slave ~]# tail -f /soft/nginx/logs/access.log
192.168.1.18 - - [22/Dec/2018:21:24:31 +0800] "GET /login.html HTTP/1.0" 503 213 "-" "ApacheBench/2.3"