Nginx防御CC攻击
CC攻击可以归为DDoS攻击的一种。他们之间都原理都是一样的,即发送大量的请求数据来导致服务器拒绝服务,是一种连接攻击。CC攻击又可分为代理CC攻击,和肉鸡CC攻击。
代理CC攻击是黑客借助代理服务器生成指向受害主机的合法网页请求,实现DOS,和伪装就叫:cc(ChallengeCollapsar)。而肉鸡CC攻击是黑客使用CC攻击软件,控制大量肉鸡,发动攻击,相比来后者比前者更难防御。
因为肉鸡可以模拟正常用户访问网站的请求。伪造成合法数据包。防御CC攻击可以通过多种方法,禁止网站代理访问,尽量将网站做成静态页面,限制连接数量等
1. 主动抑制方法 为了让Nginx支持更多的并发连接数,根据实际情况对工作线程数和每个工作线程支持的最大连接数进行调整。例如设置“worker_processes 10”和“worker_connections 1024”,那这台服务器支持的最大连接数就是10×1024=10240。
worker_processes 10; events { use epoll; worker_connections 1024; }
Nginx提供了2个限制用户连接的模块:NginxHttpLimitZoneModule和NginxHttpLimitReqModule。NginxHttpLimitZoneModule可以根据条件进行并发连接数控制。 例如可以定义以下代码: http { limit_zone my_zone $binary_remote_addr 10m; server { location /somedir/ { limit_conn my_zone 1; } } } 其中“limit_zone my_zone $binary_remote_addr 10m”的意思是定义一个名称为my_zone的存储区域、my_zone中的内容为远程IP地址、my_zone的大小为10M;“location /somedir/”的意思是针对somedir目录应用规则;
“limit_conn my_zone 1”的意思是针对上面定义的my_zone记录区记录的IP地址在指定的目录中只能建立一个连接。
NginxHttpLimitReqModule可以根据条件进行请求频率的控制。 Discuz是使用比较多的一个php论坛程序。程序目录下有比较多的可以直接访问的php文件,但其中最容易受到攻击的一般有index.php(首页)、forumdisplay.php(板块显示)、viewthread.php(帖子显示)。攻击者一般会对这些页面发起大量的请求,导致HTTP服务器连接数耗尽、mysql数据库停止响应,最终导致服务器崩溃。为了防止上述页面被攻击,我们可以设定以下的规则进行防御: 例如可以定义以下代码: http { limit_zone myzone_bbs $binary_remote_addr 10m; limit_req_zone $binary_remote_addr zone=bbs:10m rate=1r/s; ... server { ... location ~ ^/bbs/(index|forumdisplay|viewthread).php$ { limit_conn myzone_bbs 3; limit_req zone=bbs burst=2 nodelay; root html; fastcgi_pass unix:/dev/shm/php-cgi.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME /usr/share/nginx/html$fastcgi_script_name; includefastcgi_params; } } } 应用这条规则后,bbs目录下的index.php、forumdisplay.php和viewthread.php这些页面同一个IP只许建立3个连接,并且每秒只能有1个请求(突发请求可以达到2个)。
虽然这样的规则一般来说对正常的用户不会产生影响(极少有人在1秒内打开3个页面),但是为了防止影响那些手快的用户访问,可以在nginx中自定义503页面,503页面对用户进行提示,然后自动刷新。在Nginx中自定义503页面: error_page 503 /errpage/503.html; <html> < head> < title>页面即将载入....</title> < meta http-equiv=content-type c> < META NAME="ROBOTS" C> < /head> < body bgcolor="#FFFFFF"> < table cellpadding="0" cellspacing="0" border="0" width="700" align="center"height="85%"> <tr align="center" valign="middle"> <td> <table cellpadding="10" cellspacing="0" border="0" width="80%" align="center"style="font-family: Verdana, Tahoma; color: #666666; font-size: 11px"> <tr> <td valign="middle" align="center" bgcolor="#EBEBEB"> <br /><b style="font-size: 16px">页面即将载入</b> <br /><br />你刷新页面的速度过快。请少安毋躁,页面即将载入... <br /><br />[<a href="javascript:window.location.reload();"><fontcolor=#666666>立即重新载入</font></a>] <br /><br /> </td> </tr> </table> </td> </tr> < /table> < /body> < /html> < SCRIPT language=javascript> function update() { window.location.reload(); } setTimeout("update()",2000); < /script>
2. 被动防御方法 封IP地址 访问者通过浏览器正常访问网站,与服务器建立的连接一般不会超过20个,我们可以通过脚本禁止连接数过大的IP访问。
以下脚本通过netstat命令列举所有连接,将连接数最高的一个IP如果连接数超过150,则通过 iptables阻止访问: #!/bin/sh status=`netstat -na|awk '$5 ~ /[0-9]+:[0-9]+/ {print $5}' |awk -F ":" '{print $1}' |sort -n|uniq -c |sort -n|tail -n 1` NUM=`echo $status|awk '{print $1}'` IP=`echo $status|awk '{print $2}'` result=`echo "$NUM > 150" | bc` if [ $result = 1 ] then echo IP:$IP is over $NUM, BAN IT! /sbin/iptables -I INPUT -s $IP -j DROP fi
运行crontab -e,将上述脚本添加到crontab每分钟自动运行: * * * * * /root/xxxx.sh 通过apache自带的ab工具进行服务器压力测试: # ab -n 1000 -c 100 http://www.xxx.com/bbs/index.php 测试完成后,我们就可以看到系统中有IP被封的提示: tail /var/spool/mail/root 同一种CC攻击工具发起的攻击请求包总是相同的,而且和正常请求有所差异。当服务器遭遇CC攻击时,我们可以快速查看日志,分析其请求的特征,比如User-agent。
下面的是某一次CC攻击时的User-agent,Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; MyIE 3.01)Cache-Control: no-store, must-revalidate
几乎没有正常的浏览器会在User-agent中带上“must-revalidate”这样的关键字。以这个为特征进行过滤,将User-agent中带有“must-revalidate”的请求全部拒绝访问: if ($http_user_agent ~ must-revalidate) { return 403; }
图片或HTML盗链的意思是有人直接用你网站的图片地址来显示在他的网站上。最终的结果,你需要支付额外的宽带费用。这通常是在论坛和博客。建议封锁,并阻止盗链行为。 # Stop deep linking or hot linking location/images/{ valid_referers none blocked www.example.com example.com; if($invalid_referer) { return 403; } } 重定向并显示指定图片 valid_referers blocked www.example.com example.com; if($invalid_referer) { rewrite ^/images/uploads.*.(gif|jpg|jpeg|png)$ http://www.examples.com/banned.jpg last }
通过IP地址限制访问 server { listen 80; server_name www.abc.com; return 301 https://www.abc.com$request_uri; } server { listen 443 ssl; server_name www.abc.com; error_log /var/log/nginx/error_www.abc.com.log; access_log /var/log/nginx/access_www.abc.com.log; root /data/boss/zhletou/web/; index index.html; proxy_connect_timeout 600; proxy_send_timeout 600; proxy_read_timeout 600; send_timeout 600; ssl on; ssl_certificate /etc/nginx/ssl/www.abc.com.2019.pem; ssl_certificate_key /etc/nginx/ssl/www.abc.com.2019.key; ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; ssl_protocols SSLv2 SSLv3 TLSv1.2; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; allow 218.17.146.146; deny all ; } 通过密码保护目录 首先创建密码文件并增加“user”用户: 1 2 mkdir /etc/nginx/conf/.htpasswd/ htpasswd -c /etc/nginx/conf/.htpasswd/passwduser 编辑nginx.conf,加入需要保护的目录: ### Password Protect /personal-images/ and /delta/ directories ### location ~ /(personal-images/.*|delta/.*) { auth_basic "Restricted"; auth_basic_user_file /etc/nginx/conf/.htpasswd/passwd; } 一旦密码文件已经生成,你也可以用以下的命令来增加允许访问的用户: 1 htpasswd -s /etc/nginx/conf/.htpasswd/passwduserName