Main » 2011 » Март » 16 » Defend ourselves from http ddos ??and other habraeffektov
12:47
Defend ourselves from http ddos ??and other habraeffektov
A simple way to protect against HTTP DDoS - enable syn-cookies and block the bastards. But what to do if attacked by 5k-10k hosts so even with dynamic IP? Here we come to the aid frontend-backend architecture c intermediate caching! Why with an intermediate cache? And because in my case from the barrage of requests from the frontend backend died carrying for a system.

So the algorithm of action:
  • Change the port of our backend server to any other than 80 (let it be 2080)
  • Set Varnish
  • Installing and configuring lighttpd
  • Limiting number of connections from one host means iptables

So, like I was in the presence of multiple servers, it will be reviewed version of the configuration is a multi-server, but no one is stopping you all this stuff on one server =)

How to change port of your favorite Web server, I think talking is not necessary, propose to move immediately to configure Varnish.

Actually install the package:
apt-get update & & apt-get install varnish

The following is a C-like configuration file (in Ubuntu it / etc / varnish / default.vcl) approximately to the form:
backend default {
.host = "1.1.1.1"; # IP of our backend
.port = "2080"; # port
.first_byte_timeout = 300s; # without this timeout varnish did not want to take content from a backend
}

acl purge {
"localhost"; # allow cache cleaning only lokalhosta
}

sub vcl_recv {
if (req.request == "GET" & & req.url ~ "\. (jpg | jpeg | gif | ico) $") {
lookup;
}

if (req.request == "GET" & & req.url ~ "\. (css | js) $") {
lookup;
}

if (req.request == "GET" & & req.url ~ "\. (pdf | xls | vsd | doc | ppt | iso) $") {
lookup;
}

if (req.request == "POST") {
pipe;
}

if (req.request! = "GET" & & req.request! = "HEAD") {

if (req.request == "PURGE") {
if (! client.ip ~ purge) {
error 405 "Not allowed.";
}
lookup;
}

pipe;
}

if (req.http.Expect) {
pipe;
}

if (req.http. If-None-Match) {
pass;
}

if (req.http.Authenticate | | req.http.Authorization) {
pass;
}
lookup;

}

sub vcl_hit {
if (req.request == "PURGE") {
set obj.ttl = 0s;
error 200 "Purged.";
}
}

sub vcl_miss {
if (req.http.If-Modified-Since) {
pass;
}

if (req.request == "PURGE") {
error 404 "Not in cache.";
}
}

sub vcl_fetch {
if (obj.http.x-accel-redirect ~ ".*") {
set req.url = obj.http.x-accel-redirect;
restart;
}
}


Restart the varnish: service varnish restart

Now you are ready to install and configure our frontend - lighttpd.
I prefer to take lighttpd here, but nobody prevents you download it from the repositories distribution (apt-get install lighttpd).
And right configuration so long until it will look as follows:
server.modules = (
"mod_cache",
"mod_proxy",
"mod_access" ,
"mod_evasive"
)

server.network-backend = "writev"
server.max-keep-alive-requests = 4
server.max-keep -alive-idle = 4
server.max-read-idle = 10
server.max-write-idle = 30
server.event-handler = "linux-sysepoll"
server.stat-cache-engine = "disable"
server.protocol-http11 = "enable"
server.max-worker = 2 # If you have one processor, or you're running on one server then is set to 1
server.max-fds = 10000
server.max-connections = 5000
server.port = 80
server.document-root = "/ var / www"
server.errorlog = "/ var / log / lighttpd / error.log"
server.pid-file = "/ var / run / lighttpd.pid"
server.username = "www -data "
server.groupname =" www-data "
etag.use-inode =" enable "
etag.use-mtime =" enable "
etag.use- size = "enable"
server.dir-listing = "disable"
evasive.max-conns-per-ip = 3 # Allow only three concurrent connections

cache.enable = "enable" # Includes side caching lighty
cache.bases = ("/ var / spool / cache") # Here, we wake up to keep the cache
cache.max-memory-size = 40960 # 40Gb
cache . lru-remove-count = 512
cache.support-queries = "enable"
cache.dynamic-mode = "enable"
cache.refresh-pattern = (
" \. (? i) (js | css | xml | po) $ "=>" 240 ", # update js / css / xml every 4 hours and on refresh requests
" \. (? i) ( htm | html | shtml) $ "=>" 30 use-memory ", # update html / htm / shtml every 30 minutes and on refresh requests
" \. (? i) (jpg | bmp | jpeg | gif | png) $ "=>" 2880 ", # update graphics files every 2 days
" \. (? i) (rar | zip | wmv | iso | avi | mp3 | ape | rm | mpeg | mpg | wma | asf | rmvb | flv | mkv | ogg | ogm | swf | flac) $ "=>" 0 fetchall-for-range-request ", # cache media file forever
". (? i ) php $ "=>" 5 ", # update php request every 5 minutes
". "=>" 30 use-memory "#
)

mimetype.use-xattr = "enable"
include_shell "/ usr / share / lighttpd / create-mime.assign.pl"

# Bad users go to hell
$ HTTP ["useragent"] == "" {
url.access-deny = ("")
}

$ HTTP ["host"] = ~ "(^ | \.) habrahabr \. ru $" {
proxy.balance = "round-robin"
proxy.server = ("/" =>
(
("host" => "1.2.1.1", "port" = > 6081) # Sends a request
("host" => "1.2.1.2", "port" => 6081), # servers varnish
("host" => "1.2 .1.3 "," port "=> 6081),
(" host "=>" 1.2.1.4 "," port "=> 6081)
)
)
}
proxy.worked-with-mod-cache = "enable"


And finally, iptables, and a little tuning of the system:

Allow 10 connections per second with a single IP:
iptables 1-I INPUT-p tcp-m hashlimit - hashlimit-upto 10/sec - hashlimit-burst 10 - hashlimit-mode srcip - hashlimit-name HTTPD_DOS-m tcp - dport 80-m state - state NEW -j ACCEPT
Increase the number of open files:
ulimit-n 5000
Bun to sysctl.conf:
vm.swappiness = 10
vm.vfs_cache_pressure = 10000
vm.dirty_ratio = 1
vm.dirty_background_ratio = 1
vm.dirty_writeback_centisecs = 250
vm.dirty_expire_centisecs = 3000
kernel.panic = 10
net.ipv4 . tcp_fin_timeout = 15
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_sack = 1
net.core.rmem_max = 16777216
net.core.rmem_default = 16777216
net.core.netdev_max_backlog = 262144
net.core.somaxconn = 262144
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_orphans = 262144
net.ipv4. tcp_max_syn_backlog = 262144
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 2
net.ipv4.netfilter.ip_conntrack_max = 1048576
net.nf_conntrack_max = 1048576
net.ipv4.icmp_echo_ignore_all = 1
net.ipv4.netfilter.ip_conntrack_tcp_timeout_fin_wait = 15
net.ipv4.netfilter.ip_conntrack_tcp_timeout_close_wait = 15
net.ipv4.ip_local_port_range = 10000 65000

How does it work? lighttpd receives a request from the client and if it meets certain criteria (in our case this is not an empty User-agent, the client requests the domain habrahabr.ru and it's not the fourth synchronous request) sends a request to one of the servers varnish. Varnish checks its cache for the presence of the desired user-generated content gives it either from the cache or forwards the request to the backend, if the cache of the content is missing or outdated.

UPD: Thank you for your karma, suffered "Information security»
Views: 614 | Added by: w1zard | Rating: 0.0/0
Total comments: 0
Имя *:
Email *:
Код *: