昨天接到客户服务器告警,看到一个nginx+php网站正在遭受CC攻击,导致服务器复制居高不下,正常业务访问大多数时候出现502错误。

CC攻击是 DDOS(分布式拒绝服务) 的一种,DDoS是针对IP的攻击,而CC攻击的是网页。CC攻击来的IP都是真实的,分散的。数据包都是正常的数据包,攻击的请求全都是有效的请求,无法拒绝的请求。服务器可以连接,但是网页就是访问不了,也见不到特别大的异常流量,但是持续时间长,仍能造成服务器无法进行正常连接,危害更大。

Nginx和PHP网站防CC攻击解决方案步骤举例

查看服务器日志,大量IP访问网站,导致负载居高不下。user-agent也伪装成正常浏览器或者搜索引擎,不能直接通过agent屏蔽。

一、增加nginx防CC限制

在nginx.conf配置的http模块中增加类似如下代码

limit_req_zone $http_x_forwarded_for zone=one:10m rate=3r/s;
limit_conn_zone $http_x_forwarded_for zone=addr:10m;

因为网站使用了cdn,所以限制的时候使用$http_x_forwarded_for参数来获取真实IP。

然后在网站的server模块中添加

limit_req zone=one burst=5 nodelay;
limit_conn addr 3;

nginx防止CC攻击的具体配置不清楚的可以参考这篇文章:http://blog.nbqykj.cn/sysmaint/linux-os/2556.html

添加这个配置后,如果某个IP访问太频繁,打印的日志里面就会出现503错误代码。

二、分割nginx日志

出现大量日志过后,我为了后续分析方便,决定把nginx的正常日志,错误日志和拦截日志分开。

在nginx.conf配置的http模块中增加如下内容:


    map $status $normal {
        ~^2  1;
        ~^3  1;
        default 0;
    }
    map $status $notfound {
        ~^4  1;
        default 0;
    }
    map $status $abnormal {
        ~^5  1;
        default 0;
    }

定义了三个变量,$normal、$notfound、$abnormal,分别表示正常日志、拦截日志(40X)、系统异常日志。

增server模块中定义日志输出到三个文件

    access_log  /var/log/nginx/blog.nbqykj.cn.log main if=$normal;
    access_log  /var/log/nginx/blog.nbqykj.cn-error.log main if=$abnormal;
    access_log  /var/log/nginx/blog.nbqykj.cn-not-found.log main if=$notfound;

详细配置参考:http://blog.nbqykj.cn/sysmaint/linux-os/2627.html

三、禁止IP

在添加了nginx防cc攻击防护和日志分割后,可以看到在error.log日志中出现了很多503错误的非法IP,接下来就是需要把这些IP通过nginx直接禁止掉。

3.1、在nginx配置中定义真实IP变量$clientRealIp

    map $http_x_forwarded_for  $clientRealIp {
        ""      $remote_addr;
        ~^(?P<firstAddr>[0-9\.]+),?.*$  $firstAddr;
    }

3.2、nginx禁止IP控制脚本

保存在某个路径并赋给他可执行权限,例如我放在:/usr/local/bin/nginx_deny_ctl.sh

#!/bin/bash

NGINX_BIN=/usr/sbin/nginx
DENY_CONF=/etc/nginx/deny_ip
 
COLOR_RED=$( echo -e "\e[31;49m" )
COLOR_GREEN=$( echo -e "\e[32;49m" )
COLOR_RESET=$( echo -e "\e[0m" )
 
rep_info() { echo;echo -e "${COLOR_GREEN}$*${COLOR_RESET}";echo; }
rep_error(){ echo;echo -e "${COLOR_RED}$*${COLOR_RESET}";echo;exit 1; }
 
reload_nginx()
{
 $NGINX_BIN -t >/dev/null 2>&1 && \
 $NGINX_BIN -s reload && \
 return 0
}
 
pre_check()
{
 test -f $NGINX_BIN || rep_error "$NGINX_BIN not found,Plz check and edit."
 test -f $DENY_CONF || rep_error "$DENY_CONF not found,Plz check and edit." 
 MATCH_COUNT=$(show_list | grep -w $1 | wc -l)
 return $MATCH_COUNT
}
 
create_rule()
{
  test -f $DENY_CONF/$1.conf && \
  rep_error "$DENY_CONF/$1.conf already exist!."
  cat >$DENY_CONF/$1.conf<<EOF
if (\$clientRealIp ~* "$1") {
  return 403;
  break;
}
EOF
  test -f $DENY_CONF/$1.conf && \
  rep_info "$DENY_CONF/$1.conf create success!" && \
  reload_nginx
  exit 0
 
  rep_error "$DENY_CONF/$1.conf create failed!" && \
  exit 1
}

del_rule()
{
  rm -f $DENY_CONF/$1.conf
  reload_nginx
  exit 0
}
 
case $1 in
 "-a"|"--add" )
 create_rule $2;
 ;;
 "-d"|"--del" )
 del_rule $2
 ;;
esac

其中NGINX_BIN=/usr/sbin/nginx、DENY_CONF=/etc/nginx/deny_ip根据实际情况修改,创建 /etc/nginx/deny_ip 目录。

测试是否正常添加和删除

/usr/local/bin/nginx_deny_ctl.sh -a 1.2.3.4
/usr/local/bin/nginx_deny_ctl.sh -d 1.2.3.4

3.3、在网站的模块中增加deny目录

include deny_ip/*.conf;

3.4、配置fail2ban自动过滤禁止

过滤器filter:/etc/fail2ban/filter.d/nginx-bad-ip.conf

[Definition]

failregex = ^.* -.*"(GET|POST|HEAD).*HTTP.*" 503 \d+ ".*" ".*" "(-|<HOST>)"$

ignoreregex =

操作action:/etc/fail2ban/action.d/nginx-deny.conf

[Definition]
actionstart =
actionstop =
actioncheck =
actionban = /usr/local/bin/nginx_deny_ctl.sh -a <ip>
actionunban = /usr/local/bin/nginx_deny_ctl.sh -d <ip>
[Init]

配置jail:/etc/fail2ban/jail.d/nginx.local

[nginx-deny]
enabled  = true
filter   = nginx-bad-ip
action   = nginx-deny
logpath  = /var/log/nginx/mail-error.log
maxretry = 1
findtime = 10
bantime  = 86400

3.5、开启防护

在重新启动fail2ban和nginx后,观察日志和禁止目录,可以看到fail2ban自动发现了很多异常IP,然后调用action任务加入nginx禁止目录,这些IP再次访问就会直接提示403没有找到。

Nginx和PHP网站防CC攻击解决方案步骤举例

fail2ban日志

Nginx和PHP网站防CC攻击解决方案步骤举例

nginx拦截日志

Nginx和PHP网站防CC攻击解决方案步骤举例

nginx禁止目录

nginx禁止目录下的IP已经后1685个了。

今天再次观察下服务器的负载,看到攻击者没有达到目的后也就没有攻击了。

Nginx和PHP网站防CC攻击解决方案步骤举例

4、PHP优化,增加OPCache缓存

服务器维护,接下来就再给PHP安装一个缓存,优化PHP执行的速度,这样可以承受更多的压力负载。

安装opcache模块

yum install php-opcache
[opcache]
opcache.enable=1
opcache.memory_consumption=512
opcache.interned_strings_buffer=64
opcache.max_accelerated_files=100000
opcache.validate_timestamps=1
opcache.revalidate_freq=60
opcache.save_comments=1
opcache.fast_shutdown=1
Nginx和PHP网站防CC攻击解决方案步骤举例
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。