Many DDoS attacks work by exhausting the resources available to a website for handling new connections. In most cases, the tool used to generate this traffic has the ability to make HTTP requests and follow HTTP redirect messages, but lacks the sophistication to store cookies. As such, one of the most effective ways of combatting DDoS attacks is to drop connections from clients that don't store cookies during a redirect.
It's important to point out that using the solution herein may prevent at least the following legitimate uses of your website (and possibly others):
If either of the above items concern you, I would suggest seeking advice (either from the community, or through your technical support channels).
Implementing a solution in pure TrafficScript will prevent traffic from reaching the web servers. But, attackers are still free to consume connection-handling resources on the traffic manager. To make the solution more robust, we can use iptables to block traffic a bit earlier in the network stack. This solution presents us with a couple of challenges:
Even though TrafficScript cannot directly run shell commands, the Event Handling system can. We can use the event.emit() TrafficScript function to send jobs to a custom event handler shell script that will add an iptables rule that blocks the offending IP address. To expire each rule can use the at command to schedule a job that removes it. This means that we hand over the scheduling and running of that job over to the control of the OS (which is something that it was designed to do).
The overall plans looks like this:
$cookie = http.getCookie( "DDoS-Test" );
if( !$cookie ) {
# Either it's the visitor's first time to the site, or they don't support cookies
$test = http.getFormParam("cookie-test");
if( $test != "1" ) {
# It's their first time. Set the cookie, redirect to the same page
# and add a query parameter so we know they have been redirected.
# Note: if they supplied a query string or used a POST,
# we'll respond with a bare redirect
$path = http.getPath();
http.sendResponse( "302 Found", "text/plain", "",
"Location: ". string.escape( $path ) .
"?cookie-test=1\r\nSet-Cookie: DDoS-Test=1" );
} else {
# We've redirected them and attempted to set the cookie, but they have not
# accepted. Either they don't support cookies, or (more likely) they are a bot.
# Emit the custom event that will trigger the firewall script.
event.emit("firewall" , request.getremoteip());
# Pause the connection for 100 ms to give the firewall time to catch up.
# Note: This may need tuning.
connection.sleep( 100 );
# Close the connection.
connection.close("HTTP/1.1 200 OK\n");
}
}
This code will need to be applied to the virtual server as a request rule. To do that, take the following steps:
Your virtual server should now be configured to execute the rule.
#!/bin/bash
# Use getopt to collect parameters.
params=`getopt -o e:,d: -l eventtype:,duration: -- "[email protected]"`
# Evaluate the set of parameters.
eval set -- "$params"
while true; do
case "$1" in
--duration ) DURATION="$2"; shift 2 ;;
--eventtype ) EVENTTYPE="$2"; shift 2 ;;
-- ) shift; break ;;
* ) break ;;
esac
done
# Awk the IP address out of ARGV
IP=$(echo "${BASH_ARGV}" | awk ' { print ( $(NF) ) }' )
# Add a new rule to the INPUT chain.
iptables -A INPUT -s ${IP} -j DROP &&
# Queue a new job to delete the rule after DURATION minutes.
# Prevents warning about executing the command using /bin/sh from
# going in the traffic manager event log.
echo "iptables -D INPUT -s ${IP} -j DROP" |
at -M now + ${DURATION} minutes &> /dev/null
To use this script as an action program, you'll need to upload it via the GUI. To do that, take the following steps:
Now that we have a rule that emits a custom event, and a script that we can use as an action program, we can configure the event handler that will tie the two together.
First, we need to create a new event type:
Now that we have an event type, we need to create a new action:
Now that we have an action configured, the only thing that we have left to do is to connect the custom event to the new action:
That concludes the installation steps; this solution should now be live!
Testing the functionality is pretty simple for this solution. Basically, you can monitor the state of iptables while you run specific commands from a command line. To do this, ssh into your traffic manager and execute iptables -L as root. You should check this after tech of the upcoming tests.
Since I'm using a Linux machine for testing, I'm going to use the curl command to send crafted requests to my traffic manager. The 3 scenarios that I want to test are:
The respective curl commands that need to be run are:
curl -v http://<tmhost>/
curl -v http://<tmhost>/?cookie-test=1 -b "DDoS-Test=1"
curl -v http://<tmhost>/?cookie-test=1
Note: If you run these commands from your workstation, you will be unable to connect to the traffic manager in any way for a period of 10 minutes!