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. 实战

  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"

NGINX stream 路由_WAF

访问攻击测试

  • 正常访问

NGINX stream 路由_Nginx_02


NGINX stream 路由_mysql_03

  • 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

NGINX stream 路由_mysql_04


NGINX stream 路由_Nginx_05

# 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.confhttp段添加

[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空格...  
...

NGINX stream 路由_WAF_06


NGINX stream 路由_Lua_07

  1. 可防止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"