nginx,DDos
http://haibo600.blog.51cto.com/1951311/888269
1.主动抑制
为了让Nginx支持更多的并发连接数,根据实际情况对工作线程数和每个工作线程支持的最大连接数进行调整。例如设置 “worker_processes 10”和“worker_connections 1024”,那这台服务器支持的最大连接数就是10×1024=10240。
- worker_processes 10;
- events {
- use epoll;
- worker_connections 10240;
- }
Nginx 0.7开始提供了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可以根据条件进行请求频率的控制。
例如可以定义以下代码:
- http {
- limit_req_zone $binary_remote_addr zone=my_req_zone:10m rate=1r/s;
- ...
- server {
- ...
- location /somedir/ {
- limit_req_zone zone= my_req_zone burst=2;
- }
其中“limit_req_zone $binary_remote_addr zone=my_req_zone:10m rate=1r/s”的意思是定义一个名称为my_req_zone的存储区域,my_req_zone内容为远程IP地址,my_req_zone大小 为10M,my_req_zone中的平均请求速率只能为1个每秒;“location /somedir/”的意思是针对somedir目录应用规则;“limit_req_zone zone= my_req_zone burst=2”的意思是针对上面定义的my_req_zone记录区记录的IP地址在请求指定的目录中的内容时最高2个每秒的突发请求速率。
当有连接触发上诉规则时,Nginx会报“503 Service Temporarily Unavailable”的错误,停止用户请求。返回一个503,对服务器来说影响不大,只占用一个nginx的线程而已,相对来说还是很划算的。
为了测试效果,我将以上代码放入Nginx的配置文件,并编写了一个php文件显示phpinfo;另外还写了一个html文件,其中嵌入了多个 iframe调用php文件。当我打开这个html文件了,可以看到只有一个iframe中的php文件正常显示了,其他的iframe都显示503错 误。
应用举例(Discuz!)
Discuz!是使用比较多的一个php论坛程序。以Discuz!7.0为例,程序目录下有比较多的可以直接访问的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;
- include fastcgi_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;
503页面的源代码:
- <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();"><font color=#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.被动防御
虽然主动防御已经抵挡了大多数HTTP GET FLOOD攻击,但是道高一尺魔高一丈,攻击者会总会找到你薄弱的环节进行攻击。所以我们在这里也要介绍一下被动防御的一些方法。
1)封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被封的提示:
- [root@xxxxxx ~]#tail /var/spool/mail/root
- Content-Type: text/plain; charset=ANSI_X3.4-1968
- Auto-Submitted: auto-generated
- X-Cron-Env: <SHELL=/bin/sh>
- X-Cron-Env: <HOME=/root>
- X-Cron-Env: <;PATH=/usr/bin:/bin>
- X-Cron-Env: <LOGNAME=root>
- X-Cron-Env: <USER=root>
- IP:58.246.xx.xx is over 1047, BAN IT!
至此,又一次HTTP GET FLOOD防御成功。
2)根据特征码屏蔽请求(对CC攻击效果较好)
一般同一种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;
- }
本文主要介绍了nginx下的HTTP GET FLOOD防御,如果有不对的地方,希望大家可以向我提出。同时,也希望大家能够举一反三,把这种思路应用到apache、lighttpd等常见的web服务器中。
文章来源:http://www.val.so/2011/06/247.html
http://www.justwinit.cn/post/4378/
方法一:
防ddos攻击
Sysctl 修改
vi /etc/rc.local
加入如下文本
sysctl kern.ipc.maxsockets=100000 ##增加并发的socket,对于ddos很有用
sysctl kern.ipc.somaxconn=65535 ##打开文件数
sysctl net.inet.tcp.msl=2500 ##timeout时间
优化Linux内核参数
vi /etc/sysctl.conf
在末尾增加如下文本
net.core.netdev_max_backlog = 32768
net.core.somaxconn = 32768
net.core.wmem_default = 8388608
net.core.rmem_default = 8388608
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_max_syn_backlog = 65536
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_mem = 94500000 915000000 927000000
net.ipv4.tcp_max_orphans = 3276800
net.ipv4.ip_local_port_range = 1024 65535
方法二:
Nginx 内核带有限制并发和速率模块,我们可以用这个模块来缓和 VPS 的 Load。
我们需要 Nginx 的:
limit_zone
语法:limit_zone zone_name $variable memory_max_size
环境:http
limit_conn
语法:limit_conn zone_name max_clients_per_ip
环境:http, server, location
limit_rate (可选)
语法:limit_rate speed
环境:http, server, location, if in location
例子:
# 警告!例子仅供参考!记得备份原来的文件!
# Nginx.conf 的位置:/usr/local/nginx/conf/nginx.conf
http{
#... 省掉 N 字
# 下面这段受攻击时用,平常不要用
# 来自 http://cd34.com/blog/webserver/ddos-attack-mitigation/
# //------------------------------------
client_body_timeout 10;
# 该指令用于设置读取客户端请求内容的超时时间,默认是 60,
client_header_timeout 10;
# 该指令用于设置读取客户端请求 Header 头信息的超时时间,默认是 60
keepalive_timeout 10;
# 该指令用于设置 keep-alive 连接超时时间,之后服务器会中断连接,默认是 75
send_timeout 10;
# 该指令用于设置发送给客户端的应答超时时间。超时时间是指进行了两次 TCP 握手,
# 还没有转为 established 状态的时间。
# 如果超过这个时间,客户端没有响应,Nginx 关闭连接
# //----------------------------------
limit_zone one $binary_remote_addr 16m;
# one = 区名,可以随便你叫,后面要一致(看 limit_conn)
# $binary_remote_addr = 用二进制来储存客户端的地址,1 MB 可以储存 32000 个会话
}
server{
#... 省掉 N 字
limit_conn one 2;
# 允许 2 个连接(one 要跟 limit_zone 的变量对应)
limit_rate_after 5m;
# 传送 5Mb 后开始限速(就算没用上,默认是 1m)
limit_rate 100k;
# 限速为 100KB/秒
}
总结:
1、总速度可以去到 200KB/秒左右,一个连接可以去到 100KB,两个就 200KB(数学题)
2、如果你在下载, 又打开网页就,会返回 503 “Service unavailable”,因为太多连接
3、缓解 DDoS 还得靠那几个 timeout 的部分
重要提醒:
1、限制模块是不能防止 DDoS,它是用来减小 Load
2、真正的方法应该是,找出那个攻击者 IP,再用 iptables 封掉它
3、非必要时,不要用这个限制模块,它会给你的网站带来不便
http://www.cnblogs.com/geekma/archive/2012/09/06/2673222.html
近期由于工作需要,做了些防DDOS攻击的研究,发现nginx本身就有这方面的模块ngx_http_limit_req_module和ngx_http_limit_conn_module。
一、基本介绍
1.ngx_http_limit_req_module
配置格式及说明:
设置一个缓存区保存不同key的状态,这里的状态是指当前的过量请求数。而key是由variable指定的,是一个非空的变量,我们这里使用$binary_remote_addr,表示源IP为key值。
limit_req_zone $variable zone=name:size rate=rate;
指定要进行限制的缓存区和最大的请求到达后有多少个请求放入延迟队列(其它的直接丢弃)。如果不希望请求数达到上限而被延迟,就需要使用nodelay。
limit_req zone=name [burst=number] [nodelay];
例子:
缓存区为10M,请求限制为每秒1次,延迟队列为5
http { limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s; ... server { ... location /search/ { limit_req zone=one burst=5; }
}
2.ngx_http_limit_conn_module
配置格式及说明:
设置一个缓存区保存不同key的状态。我们这里使用源IP来作为key,以此限制每个源IP的链接数
limit_conn_zone $binary_remote_addr zone=addr:10m;
指定限制的缓存区,并指定每个key的链接个数
limit_conn zone number;
例子:
http { limit_conn_zone $binary_remote_addr zone=addr:10m; ... server { ... location /download/ { limit_conn addr 1; } }
二、实际应用
如果作为代理服务器,我们需要限制每个用户的请求速度和链接数量,但是,由于一个页面有多个子资源,如果毫无选择的都进行限制,那就会出现很多不必要的麻烦,如:一个页面有40个子资源,那么如果想让一个页面完整的显示,就需要将请求速度和连接数都调整到40,以此达到不阻塞用户正常请求,而这个限制,对服务器性能影响很大,几百用户就能把一台nginx的处理性能拉下来。
所以我们需要制定哪些请求是需要进行限制的,如html页面;哪些是不需要限制的,如css、js、图片等,这样就需要通过配置对应的location进一步细化。
注:location介绍见最后附录
我们不对css、js、gif、png,jpg等进行连接限制,而对除此之外的链接进行限制
http { limit_conn_zone $binary_remote_addr zone=addr:10m; limit_req_zone $binary_remote_addr zone=one:10m rate=5r/s; ... server { ... location ~ .*\.(gif|png|css|js|icon)$ { proxy_set_header Host $http_host; proxy_set_header X-Real_IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location ~* .*\.(jpeg|jpg|JPG)$ { proxy_set_header Host $http_host; proxy_set_header X-Real_IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # image_filter resize 480 -; # image_filter_jpeg_quality 50; # image_filter_sharpen 10; # image_filter_buffer 4M; } location / { proxy_set_header Host $http_host; proxy_set_header X-Real_IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; #limit limit_conn addr 3; limit_req zone=one burst=5; } }
附录:Location配置简单介绍(转自http://blog.sina.com.cn/s/blog_97688f8e0100zws5.html)
FreeBSD, network card: Intel fxp, port: 100Мбит, polling, http accept-filter.
in sysctl:
sysctl kern.maxfiles=90000 sysctl kern.maxfilesperproc=80000 sysctl net.inet.tcp.blackhole=2 sysctl net.inet.udp.blackhole=1 sysctl kern.polling.burst_max=1000 sysctl kern.polling.each_burst=50 sysctl kern.ipc.somaxconn=32768 sysctl net.inet.tcp.msl=3000 sysctl net.inet.tcp.maxtcptw=40960 sysctl net.inet.tcp.nolocaltimewait=1 sysctl net.inet.ip.portrange.first=1024 sysctl net.inet.ip.portrange.last=65535 sysctl net.inet.ip.portrange.randomized=0
in nginx configuration:
worker_processes 1; worker_rlimit_nofile 80000; events { worker_connections 50000; } server_tokens off; log_format IP `$remote_addr'; reset_timedout_connection on; listen xx.xx.xx.xx:80 default rcvbuf=8192 sndbuf=16384 backlog=32000 accept_filter=httpready;
In the following way it is possible to realize filtration of url, in example for POST
index.php?action=login which is with empty referral.
set $add 1; location /index.php { limit_except GET POST { deny all; } set $ban ""; if ($http_referer = "" ) {set $ban $ban$add;} if ($request_method = POST ) {set $ban $ban$add;} if ($query_string = "action=login" ){set $ban $ban$add;} if ($ban = 111 ) { access_log /var/log/[133]nginx/ban IP; return 404; } proxy_pass http://127.0.0.1:8000; #here is a patch }
Further we cut it at pf level – loaded into IP table, hosts from which came too many hits.
PF with tables works very quickly. Sources for parsing of logs (ddetect) you can find on http://www.comsys.com.ua/files
Then Cron used once in a minute, to add into ip tables new IPs from a log.
25 Mbyte DDoS, which cuts IPs, the rests fall on nginx which by it is criterion pass IPs and the rests passed on the apache – LA 0, site works.