DDOS attack mitigation
Today we had a DDOS attack on one of our clients. They were running prefork with mod_php5 with a rather busy application. While we initially started filtering IP addresses using iptables and a few crudely hacked rules, we knew something had to be done that was a little more permanent. Moving to MPM-Worker with PHP served with FastCGI seemed reasonable, but, looking at the history of the attacks on this machine, I believe Apache still would have been vulnerable since we cannot filter the requests early enough in Apache’s request handler.
Apache does have the ability to fight some DDOS attacks using mod_security and mod_evasive, but, this particular attack was designed to affect apache prior to the place where these modules hook into the request. This also precludes using fail2ban. We could run mod_forensic or mod_logio to assist fail2ban, but, it is still a stopgap measure.
We could have used some Snort rules and tied those to iptables, but, that is a rather bad solution to the problem.
While we could have used Varnish, their application would have had some issues. mod_rpaf can help by adjusting the REMOTE_ADDR to take the value from X-Forwarded-For that Varnish sets. mod_geoip actually inserts itself before mod_rpaf, so, we would have needed to make a modification to mod_geoip and recompiled it. I’m not sure how Varnish would have handled Slowloris and we had to fix this now.
Putting them behind a Layer 7 load balancer would have isolated the origin server and handled the brunt of the attack on the load balancer, but, again we would have needed mod_rpaf and some modifications to their code.
In the end, Lighttpd and Nginx appeared to be the only documented solution. After the conversion, we did find documentation that said Varnish and Squid were immune to Slowloris. With Nginx or Lighttpd, we didn’t have IP address issues to contend with, it would be easy enough to modify the fastcgi config to pass the GEOIP information in the same request variable that their application expected. We knew we had to run PHP under FastCGI, so, we might as well pick a tool where we can block the attack in the webserver without having to worry about firewall rules. We did put a few firewall rules in place to block the larger offenders.
in the http { } section of our nginx config, we added:
client_body_timeout 10; client_header_timeout 10; keepalive_timeout 10; send_timeout 10; limit_zone limit_per_ip $binary_remote_addr 16m;
and in the server { } section, we added:
limit_conn limit_per_ip 5;
Since each server was expecting to handle one or two requests from each IP, this gave us a little headroom while solving the problem in the right place.
I believe Varnish would have held the connection and wouldn’t have sent a request to the backend which makes it fairly versatile as a tool to deal with DDOS attacks. While I do like the ability to block certain requests in VCL, the methods listed to fight this type of attack appeared to favor a non-threaded webserver. Varnish in front of Apache would have worked, but, we already knew we needed to move from Apache at some point with this client and this gave us an opportunity to shift them while under the gun.
Wouldn’t have had it any other way.
April 26th, 2010 at 9:12 pm
limit_conn limit_per_ip 5; So, I worked in an office before where I remember more than 5 people visiting the same site… wouldn’t that prevent more than 5 people?
April 27th, 2010 at 9:29 pm
If all five people at the office hit the page at the same time, yes, a legitimate connection could be blocked. If a person from the office hits the site seconds after another person has visited, their requests will not be blocked.
It isn’t something you would want to run with longterm, but, as a temporary measure, locking down things so that 95% of the people can still access it without a problem is much better than a site that is not available to 95% of the surfers.
May 23rd, 2010 at 12:29 pm
As of Apache 2.2.15, there is now a reqtimeout module that hooks Apache early enough to prevent the effect Slowloris attack with a method that is a little better than IP connection limits.
With the new module, you can set read limits and data request-rate limits to drop connections.
June 9th, 2010 at 12:39 pm
rpaf-0.6 inserts itself before mod_geoip so it should work ok