Thursday 28 October 2010

Prevent DOS with iptables

Prevent DOS with iptables


After a recent conversation on the Ubuntu Forums I wanted to post an example of using iptables.


Of course there are several types of DOS attacks , in this post I will demonstrating the use if iptables to limit the traffic on port 80.



The goal is to keep your web server “responsive” to legitimate traffic, but to throttle back on excessive (potential DOS) traffic.


In this demonstration iptables is configured :



  1. The default policy is ACCEPT (to prevent lockout in the event of flushing the rules with iptables -F).

  2. “Legitimate” traffic is then allowed. In this example I am allowing traffic only on port 80.

  3. All other traffic is then blocked at the end of the INPUT chain (the final rule in the INPUT chain is to DROP all traffic).



The rules I will demonstrate are as follows:


First rule : Limit NEW traffic on port 80


sudo iptables -A INPUT -p tcp --dport 80 -m state --state NEW -m limit --limit 50/minute --limit-burst 200 -j ACCEPT



Lets break that rule down into intelligible chunks.


-p tcp --dport 80 => Specifies traffic on port 80 (Normally Apache, but as you can see here I am using nginx).


-m state NEW => This rule applies to NEW connections.


-m limit --limit 50/minute --limit-burst 200 -j ACCEPT =>This is the essence of preventing DOS.




  • “--limit-burst” is a bit confusing, but in a nutshell 200 new connections (packets really) are allowed before the limit of 50 NEW connections (packets) per minute is applied.


For a more technical review of this rule, see this netfilet page. Scroll down to a bit to the “limit” section.


Second rule – Limit established traffic



This rule applies to RELATED and ESTABLISHED all traffic on all ports, but is very liberal (and thus should not affect traffic on port 22 or DNS).


If you understood the above rule, you should understand this one as well.


sudo iptables -A INPUT -m state --state RELATED,ESTABLISHED -m limit --limit 50/second --limit-burst 50 -j ACCEPT


In summary, 50 ESTABLISHED (and/or RELATED) connections (packets really) are allowed before the limit of 50 ESTABLISHED (and/or RELATED) connections (packets) per second is applied.


Do not let that rule fool you, although it seems very open, it does put some limits on your connections.



Test it for yourself, try using the first rule with and without the second rule.


Full set of rules


After the above commands, here is the complete set of rules I am testing:



iptables-save
# Generated by iptables-save v1.4.4 on --
*nat
:PREROUTING ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT
# Completed on --
# Generated by iptables-save --
*mangle
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
COMMIT
# Completed on --
# Generated by iptables-save v1.4.4 on --

*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -m limit --limit 50/sec --limit-burst 50 -j ACCEPT
-A INPUT -p icmp -m limit --limit 1/sec -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -m state --state NEW -m limit --limit 50/min --limit-burst 200 -j ACCEPT
-A INPUT -j LOG
-A INPUT -j DROP
-A FORWARD -j DROP
-A OUTPUT -o lo -j ACCEPT
COMMIT
# Completed on --

This rule set is for demonstration only and is NOT a complete set of rules for a web server. Do no use this rule set unmodified on a production server.


Testing the rule set


Human interaction



Open Firefox, point it to your web page. The web page should load nice and fast.


Hit F5 repetitively, load the page as fast as you can. Your web site should remain nice and responsive.


So far, so good, we want our site to remain responsive.


Simulated DOS


Actual DOS attacks are many times faster then humans, here I will use ab.


See this link or the Apache documentation for information of ab.



Baseline, without the above 2 rules


ab -n 100 -c 10 http://bodhi's_test_server.com/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking bodhi's_test_server.com (be patient).....done

Server Software: nginx
Server Hostname: bodhi's_test_server.com
Server Port: 80

Document Path: /
Document Length: 59786 bytes

Concurrency Level: 10
Time taken for tests: 13.174 seconds
Complete requests: 100
Failed requests: 0
Write errors: 0
Total transferred: 6002700 bytes
HTML transferred: 5978600 bytes
Requests per second: 7.59 [#/sec] (mean)
Time per request: 1317.369 [ms] (mean)
Time per request: 131.737 [ms] (mean, across all concurrent requests)
Transfer rate: 444.98 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 122 129 2.2 128 134
Processing: 1151 1182 19.1 1177 1260
Waiting: 125 132 8.2 128 170
Total: 1280 1310 19.3 1305 1390

Percentage of the requests served within a certain time (ms)
50% 1305
66% 1313
75% 1316
80% 1321
90% 1328
95% 1354
98% 1386
99% 1390
100% 1390 (longest request)

Notice:

Requests per second: 7.59 [#/sec] .

Total time for requests: 13 seconds .

(Data) Transfer rate: 444.98 [Kbytes/sec] .



With the above rules


First attempt:



ab -n 100 -c 10 http://bodhi's_test_server.com/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking bodhi's_test_server.com (be patient)...apr_poll: The timeout specified has expired (70007)
Total of 99 requests completed

Oh no ! timed out, LOL


Second attempt (I reduced the number of requests to 90):



ab -n 90 -c 10 http://bodhi's_test_server.com/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking bodhi's_test_server.com (be patient).....done

Server Software: nginx
Server Hostname: bodhi's_test_server.com
Server Port: 80

Document Path: /
Document Length: 59786 bytes

Concurrency Level: 10
Time taken for tests: 69.684 seconds
Complete requests: 90
Failed requests: 0
Write errors: 0
Total transferred: 5402430 bytes
HTML transferred: 5380740 bytes
Requests per second: 1.29 [#/sec] (mean)
Time per request: 7742.658 [ms] (mean)
Time per request: 774.266 [ms] (mean, across all concurrent requests)
Transfer rate: 75.71 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 123 128 4.3 127 155
Processing: 1036 6269 10081.4 1921 51059
Waiting: 125 1240 5908.7 128 49656
Total: 1159 6396 10081.1 2044 51186

Percentage of the requests served within a certain time (ms)
50% 2044
66% 2981
75% 5478
80% 7047
90% 20358
95% 27356
98% 48218
99% 51186
100% 51186 (longest request)

Notice :


Requests per second: 1.29 [#/sec] (mean)

Total time for requests: 69 seconds.

(Data) Transfer rate: 75.71 [Kbytes/sec] [Kbytes/sec].


For those unfamiliar with ab, that is a “minor” DOS


For comparison, here is what ab can do to the server (iptables was flushed [disabled]):


ab -n 1000 -c 100 http://bodhi's_test_server.com/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking bodhi's_test_server.com (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests

Server Software: nginx
Server Hostname: bodhi's_test_server.com
Server Port: 80

Document Path: /
Document Length: 58708 bytes

Concurrency Level: 100
Time taken for tests: 59.324 seconds
Complete requests: 1000
Failed requests: 945
(Connect: 0, Receive: 0, Length: 945, Exceptions: 0)
Write errors: 0
Total transferred: 59190450 bytes
HTML transferred: 58945935 bytes
Requests per second: 16.86 [#/sec] (mean)
Time per request: 5932.368 [ms] (mean)
Time per request: 59.324 [ms] (mean, across all concurrent requests)
Transfer rate: 974.37 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 127 908 817.9 788 8016
Processing: 735 4779 1805.2 4368 15707
Waiting: 128 981 827.2 811 12143
Total: 1058 5687 1880.8 5269 17450

Percentage of the requests served within a certain time (ms)
50% 5269
66% 5899
75% 6340
80% 6863
90% 8078
95% 9001
98% 10937
99% 11730
100% 17450 (longest request)



Notice :

Requests per second: 16.86 [#/sec]

Total time for requests: 69 seconds.

(Data) Transfer rate: 974.37 [Kbytes/sec] .


As you can see, the server has no problem dishing out 974.37 [Kbytes/sec] !!!


Closing remarks



Hopefully you now understand this “simple” example limiting a DOS on port 80.


With these rules your web site remains responsive to human interaction in firefox. Go ahead, hit F5 (refresh the page) as fast as you can, see if you can get your web page to slow down =) .


The difference is that as with a DOS attack, ab is hitting the server faster then you can with F5 , so your site is responsive to “normal” activity, but blocks DOS.


Obviously this is but one example and there are several types of DOS attacks. The goal is to demonstrate the use of iptables using a few “simple” rules.



You task is to take this knowledge and apply it to you own server.

No comments:

Post a Comment