Use a load-balancer as a first row of defense against DDOS
We’ve seen recently more and more DOS and DDOS attacks. Some of them were very big, requiring thousands of computers…
But in most cases, this kind of attacks are made by a few computers aiming to make a service or website unavailable, either by sending it too many requests or by taking all its available resources, preventing regular users to use the service.
Some attacks targets known vulnerabilities of widely used applications.
In the present article, we’ll explain how to take advantage of an application delivery controller to protect your website and application against DOS, DDOS and vulnerability scans.
Why using a LB for such protection since a firewall and a Web Application Firewall (aka WAF) could already do the job?
Well, the Firewall is not aware of the application layer but would be useful to pretect against SYN flood attacks. That’s why we saw recently application layer firewalls: Web Application Firewalls, also known as WAF.
Well, since the load balancer is in front of the platform, it can be a good partner for the WAF, filtering out 99% of the attacks, which are managed by script kiddies. The WAF can then happily clean up the remaining attacks.
Well, maybe you don’t need a WAF and you want to take advantage of your Aloha and save some money ;).
Note that you need an application layer load-balancer, like Aloha or OpenSource HAProxy to be efficient.
TCP syn flood attacks
The syn flood attacks consist in sending as many TCP syn packets as possible to a single server trying to saturate it or at least, saturating its uplink bandwith.
If you’re using the Aloha load-balancer, you’re already protected against this kind of attacks: the Aloha includes mechanism to protect you.
The TCP syn flood attack mitigation capacity may vary depending on your Aloha box.
It you’re running your own LB based on HAProxy or HAPee, you should have a look at the sysctl below (edit /etc/sysctl.conf or play with sysctl command):
# Protection SYN flood
net.ipv4.tcp_syncookies =
net.ipv4.conf.all.rp_filter =
net.ipv4.tcp_max_syn_backlog =
Note: If the attack is very big and saturates your internet bandwith, the only solution is to ask your internet access provider to null route the attackers IPs on its core network.
Slowloris like attacks
For this kind of attack, the clients will send very slowly their requests to a server: header by header, or even worst character by character, waiting long time between each of them.
The server have to wait until the end of the request to process it and send back its response.
The purpose of this attack is to prevent regular users to use the service, since the attacker would be using all the available resources with very slow queries.
In order to protect your website against this kind of attack, just setup the HAProxy option “timeout http-request”.
You can set it up to 5s, which is long enough.
It tells HAProxy to let five seconds to a client to send its whole HTTP request, otherwise HAProxy would shut the connection with an error.
For example:
# On Aloha, the global section is already setup for you
# and the haproxy stats socket is available at /var/run/haproxy.stats
global
stats socket ./haproxy.stats level admin defaults
option http-server-close
mode http
timeout http-request 5s
timeout connect 5s
timeout server 10s
timeout client 30s listen stats
bind 0.0.0.0:
stats enable
stats hide-version
stats uri /
stats realm HAProxy\ Statistics
stats auth admin:admin frontend ft_web
bind 0.0.0.0: # Spalreadylit static and dynamic traffic since these requests have different impacts on the servers
use_backend bk_web_static if { path_end .jpg .png .gif .css .js } default_backend bk_web # Dynamic part of the application
backend bk_web
balance roundrobin
cookie MYSRV insert indirect nocache
server srv1 192.168.1.2: check cookie srv1 maxconn
server srv2 192.168.1.3: check cookie srv2 maxconn # Static objects
backend bk_web_static
balance roundrobin
server srv1 192.168.1.2: check maxconn
server srv2 192.168.1.3: check maxconn
To test this configuration, simply open a telnet to the frontend port and wait for 5 seconds:
telnet 127.0.0.1 8080
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
HTTP/1.0 408 Request Time-out
Cache-Control: no-cache
Connection: close
Content-Type: text/html <h1>408 Request Time-out</h1>
Your browser didn't send a complete request in time. Connection closed by foreign host.
Unfair users, AKA abusers
By unfair users, I mean users (or scripts) which have an abnormal behavior on your website:
- too many connections opened
- new connection rate too high
- http request rate too high
- bandwith usage too high
- client not respecting RFCs (IE for SMTP)
How does a regular browser works?
Before trying to protect your website from weird behavior, we have to define what a “normal” behavior is!
This paragraphs gives the main lines of how a browser works and there may be some differences between browsers.
So, when one wants to browse a website, we use a browser: Chrome, Firefox, Internet Explorer, Opera are the most famous ones.
After typing the website name in the URL bar, the browser will look like for the IP address of your website.
Then it will establish a tcp connection to the server, downloading the main page, analyze its content and follow its links from the HTML code to get the objects required to build the page: javascript, css, images, etc…
To get the objects, it may open up to 6 or 7 TCP connections per domain name.
Once it has finished to download the objects, it starts aggregating everything then print out the page.
Limiting the number of connections per users
As seen before, a browser opens up 5 to 7 TCP connections to a website when it wants to download objetcs and they are opened quite quickly.
One can consider that somebody having more than 10 connections opened is not a regular user.
The configuration below shows how to do this limitation in the Aloha and HAProxy:
This configuration also applies to any kind of TCP based application.
The most important lines are from 25 to 32.
# On Aloha, the global section is already setup for you
# and the haproxy stats socket is available at /var/run/haproxy.stats
global
stats socket ./haproxy.stats level admin defaults
option http-server-close
mode http
timeout http-request 5s
timeout connect 5s
timeout server 10s
timeout client 30s listen stats
bind 0.0.0.0:
stats enable
stats hide-version
stats uri /
stats realm HAProxy\ Statistics
stats auth admin:admin frontend ft_web
bind 0.0.0.0: # Table definition
stick-table type ip size 100k expire 30s store conn_cur # Allow clean known IPs to bypass the filter
tcp-request connection accept if { src -f /etc/haproxy/whitelist.lst }
# Shut the new connection as long as the client has already opened
tcp-request connection reject if { src_conn_cur ge }
tcp-request connection track-sc1 src # Split static and dynamic traffic since these requests have different impacts on the servers
use_backend bk_web_static if { path_end .jpg .png .gif .css .js } default_backend bk_web # Dynamic part of the application
backend bk_web
balance roundrobin
cookie MYSRV insert indirect nocache
server srv1 192.168.1.2: check cookie srv1 maxconn
server srv2 192.168.1.3: check cookie srv2 maxconn # Static objects
backend bk_web_static
balance roundrobin
server srv1 192.168.1.2: check maxconn
server srv2 192.168.1.3: check maxconn
- NOTE: if several domain name points to your frontend, then you may want to increase the conn_cur limit. (Remember a browser opens its 5 to 7 TCP connections per domain name).
- NOTE2: if several users are hidden behind the same IP (NAT or proxy), this configuration may have a negative impact for them. You can whitelist these IPs.
Testing the configuration
run an apache bench to open 10 connections and doing request on these connections:
ab -n 50000000 -c 10 http://127.0.0.1:8080/
Watch the table content on the haproxy stats socket:
echo "show table ft_web" | socat unix:./haproxy.stats -
# table: ft_web, type: ip, size:102400, used:1
0x7afa34: key=127.0.0.1 use=10 exp=29994 conn_cur=10
Let’s try to open an eleventh connection using telnet:
telnet 127.0.0.1 8080
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Connection closed by foreign host.
Basically, opened connections can keep on working, while a new one can’t be established.
Limiting the connection rate per user
In the previous chapter, we’ve seen how to protect ourselves from somebody who wants to open more than X connections at the same time.
Well, this is good, but something which may kill performance would to allow somebody to open and close a lot of tcp connections over a short period of time.
As we’ve seen previously, a browser will open up to 7 TCP connections in a very short period of time (a few seconds). One can consider that somebody having more than 20 connections opened over a period of 3 seconds is not a regular user.
The configuration below shows how to do this limitation in the Aloha and HAProxy:
This configuration also applies to any kind of TCP based application.
The most important lines are from 25 to 32.
# On Aloha, the global section is already setup for you
# and the haproxy stats socket is available at /var/run/haproxy.stats
global
stats socket ./haproxy.stats level admin defaults
option http-server-close
mode http
timeout http-request 5s
timeout connect 5s
timeout server 10s
timeout client 30s listen stats
bind 0.0.0.0:
stats enable
stats hide-version
stats uri /
stats realm HAProxy\ Statistics
stats auth admin:admin frontend ft_web
bind 0.0.0.0: # Table definition
stick-table type ip size 100k expire 30s store conn_rate(3s) # Allow clean known IPs to bypass the filter
tcp-request connection accept if { src -f /etc/haproxy/whitelist.lst }
# Shut the new connection as long as the client has already opened
tcp-request connection reject if { src_conn_rate ge }
tcp-request connection track-sc1 src # Split static and dynamic traffic since these requests have different impacts on the servers
use_backend bk_web_static if { path_end .jpg .png .gif .css .js } default_backend bk_web # Dynamic part of the application
backend bk_web
balance roundrobin
cookie MYSRV insert indirect nocache
server srv1 192.168.1.2: check cookie srv1 maxconn
server srv2 192.168.1.3: check cookie srv2 maxconn # Static objects
backend bk_web_static
balance roundrobin
server srv1 192.168.1.2: check maxconn
server srv2 192.168.1.3: check maxconn
- NOTE2: if several users are hidden behind the same IP (NAT or proxy), this configuration may have a negative impact for them. You can whitelist these IPs.
Testing the configuration
run 10 requests with ApacheBench, everything may be fine:
ab -n 10 -c 1 -r http://127.0.0.1:8080/
Using socat we can watch this traffic in the stick-table:
# table: ft_web, type: ip, size:102400, used:1
0x11faa3c: key=127.0.0.1 use=0 exp=28395 conn_rate(3000)=10
Running a telnet to run a eleventh request and the connections get closed:
telnet 127.0.0.1 8080
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Connection closed by foreign host.
Limiting the HTTP request rate
Even if in the previous examples, we were using HTTP as the protocol, we based our protection on layer 4 information: number or opening rate of TCP connections.
An attacker could respect the number of connection we would set by emulating the behavior of a regular browser.
Now, let’s go deeper and see what we can do on HTTP protocol.
The configuration below tracks HTTP request rate per user on the backend side, blocking abusers on the frontend side if the backend detects abuse.
# On Aloha, the global section is already setup for you
# and the haproxy stats socket is available at /var/run/haproxy.stats
global
stats socket ./haproxy.stats level admin defaults
option http-server-close
mode http
timeout http-request 5s
timeout connect 5s
timeout server 10s
timeout client 30s listen stats
bind 0.0.0.0:
stats enable
stats hide-version
stats uri /
stats realm HAProxy\ Statistics
stats auth admin:admin frontend ft_web
bind 0.0.0.0: # Use General Purpose Couter (gpc) in SC1 as a global abuse counter
# Monitors the number of request sent by an IP over a period of seconds
stick-table type ip size 1m expire 10s store gpc0,http_req_rate(10s)
tcp-request connection track-sc1 src
tcp-request connection reject if { src_get_gpc0 gt } # Split static and dynamic traffic since these requests have different impacts on the servers
use_backend bk_web_static if { path_end .jpg .png .gif .css .js } default_backend bk_web # Dynamic part of the application
backend bk_web
balance roundrobin
cookie MYSRV insert indirect nocache # If the source IP sent or more http request over the defined period,
# flag the IP as abuser on the frontend
acl abuse src_http_req_rate(ft_web) ge
acl flag_abuser src_inc_gpc0(ft_web)
tcp-request content reject if abuse flag_abuser server srv1 192.168.1.2: check cookie srv1 maxconn
server srv2 192.168.1.3: check cookie srv2 maxconn # Static objects
backend bk_web_static
balance roundrobin
server srv1 192.168.1.2: check maxconn
server srv2 192.168.1.3: check maxconn
- NOTE: if several users are hidden behind the same IP (NAT or proxy), this configuration may have a negative impact for them. You can whitelist these IPs.
Testing the configuration
run 10 requests with ApacheBench, everything may be fine:
ab -n 10 -c 1 -r http://127.0.0.1:8080/
Using socat we can watch this traffic in the stick-table:
# table: ft_web, type: ip, size:1048576, used:1
0xbebbb0: key=127.0.0.1 use=0 exp=8169 gpc0=1 http_req_rate(10000)=10
Running a telnet to run a eleventh request and the connections get closed:
telnet 127.0.0.1 8080
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Connection closed by foreign host.
Detecting vulnerability scans
Vulnerability scans could generate different kind of errors which can be tracked by Aloha and HAProxy:
- invalid and truncated requests
- denied or tarpitted requests
- failed authentications
- 4xx error pages
HAProxy is able to monitor an error rate per user then can take decision based on it.
# On Aloha, the global section is already setup for you
# and the haproxy stats socket is available at /var/run/haproxy.stats
global
stats socket ./haproxy.stats level admin defaults
option http-server-close
mode http
timeout http-request 5s
timeout connect 5s
timeout server 10s
timeout client 30s listen stats
bind 0.0.0.0:
stats enable
stats hide-version
stats uri /
stats realm HAProxy\ Statistics
stats auth admin:admin frontend ft_web
bind 0.0.0.0: # Use General Purpose Couter in SC1 as a global abuse counter
# Monitors the number of errors generated by an IP over a period of seconds
stick-table type ip size 1m expire 10s store gpc0,http_err_rate(10s)
tcp-request connection track-sc1 src
tcp-request connection reject if { src_get_gpc0 gt } # Split static and dynamic traffic since these requests have different impacts on the servers
use_backend bk_web_static if { path_end .jpg .png .gif .css .js } default_backend bk_web # Dynamic part of the application
backend bk_web
balance roundrobin
cookie MYSRV insert indirect nocache # If the source IP generated or more http request over the defined period,
# flag the IP as abuser on the frontend
acl abuse src_http_err_rate(ft_web) ge
acl flag_abuser src_inc_gpc0(ft_web)
tcp-request content reject if abuse flag_abuser server srv1 192.168.1.2: check cookie srv1 maxconn
server srv2 192.168.1.3: check cookie srv2 maxconn # Static objects
backend bk_web_static
balance roundrobin
server srv1 192.168.1.2: check maxconn
server srv2 192.168.1.3: check maxconn
Testing the configuration
run an apache bench, pointing it on a purposely wrong URL:
ab -n 10 http://127.0.0.1:8080/dlskfjlkdsjlkfdsj
Watch the table content on the haproxy stats socket:
echo "show table ft_web" | socat unix:./haproxy.stats -
# table: ft_web, type: ip, size:1048576, used:1
0x8a9770: key=127.0.0.1 use=0 exp=5866 gpc0=1 http_err_rate(10000)=11
Let’s try to run the same ab command and let’s get the error:
apr_socket_recv: Connection reset by peer (104)
which means that HAProxy has blocked the IP address
Notes
- We could combine configuration example above together to improve protection. This will be described later in an other article
- The numbers provided in the examples may be different for your application and architecture. Bench your configuration properly before applying in production.
Related articles
- Fight spam with early talking detection
- Protect Apache against Apache-killer script
- Protect your web server against slowloris
Links
div { margin-top: 1em; } #google_ads_div_wpcom_below_post_adsafe_ad_container { display: block !important; }
-->
Use a load-balancer as a first row of defense against DDOS的更多相关文章
- 使用 Load Balancer,Corosync,Pacemaker 搭建 Linux 高可用集群
由于网络架构的原因,在一般虚拟机或物理环境中常见的用 VIP 来实现双机高可用方案,无法照搬到 Azure 平台.但利用 Azure 平台提供的负载均衡或者内部负载均衡功能,可以达到类似的效果. 本文 ...
- 负载均衡server load balancer
负载均衡(Server Load Balancer,简称SLB)是对多台云服务器进行流量分发的负载均衡服务.SLB可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性. ( ...
- Feign报错Caused by: com.netflix.client.ClientException: Load balancer does not have available server for client
问题描述 使用Feign调用微服务接口报错,如下: java.lang.RuntimeException: com.netflix.client.ClientException: Load balan ...
- Load balancer does not have available server for client
最近在研究spring-cloud,研究zuul组件时发生下列错误: Caused by: com.netflix.client.ClientException: Load balancer does ...
- Data Center手册(3): Load Balancer
Load Balancer的类型 DNS Round-Robin 这是一种很常见的分流的方式,具体配置如下: name server有一个zone文件,对于同一个domain,有多个IP www.ex ...
- [译]Ocelot - Load Balancer
原文 可以对下游的服务进行负载均衡. 提供了下面几种负载均衡: LeastConnection - tracks which services are dealing with requests an ...
- CentOS7+CDH5.14.0安装CDH错误排查:Hue错误: Load Balancer 该角色的进程启动失败
Hue错误: Load Balancer 该角色的进程启动失败 解决办法:主机能够联网情况下,直接运行如下命令即可在线安装openssl.httpd 需要提前安装环境 httpd, mod_ssl ...
- NGINX Load Balancing - HTTP Load Balancer
This chapter describes how to use NGINX and NGINX Plus as a load balancer. Overview Load balancing a ...
- Azure Load Balancer : 动态扩展
笔者在前文<Azure Load Balancer : 支持 IPv6>中介绍了如何通过 PowerShell 脚本创建支持 IPv6 的 Load Balancer.本文我们接着介绍如何 ...
随机推荐
- [TenserFlow学习笔记]——安装
最近人工智能.深度学习.机器学习等词汇很是热闹,所以想进一步学习一下.不一定吃这口饭,但多了解一下没有坏处.接下来将学习到的一些知识点做一下记录. 1.安装环境 在VMWare虚拟机中安装最新版本的U ...
- [Java web]Spring+Struts2+Hibernate整合过程(2)
摘要 上篇文章介绍了一种整合方式,不妨就叫做有hibernate配置文件的方式,这里介绍一种不用hibernate.cfg.xml的一种配置方式,为了方便,就仍在上篇的demo中,继续修改了. 步骤 ...
- Hive总结(八)Hive数据导出三种方式
今天我们再谈谈Hive中的三种不同的数据导出方式. 依据导出的地方不一样,将这些方式分为三种: (1).导出到本地文件系统. (2).导出到HDFS中: (3).导出到Hive的还有一个表中. 为了避 ...
- ds18b20采集温度并上报服务器
交叉编译器:arm-linux-gcc-4.5.4 Linux内核版本:Linux-3.0 主机操作系统:Centos 6.5 开发板:FL2440 温度传感器:ds18b20 注:此程序的客户端是在 ...
- ckeditor 上传图片解决跨域问题
前后端分离ckeditor跨域问题处理 这个跨域问题很常见,特别是前后端分离的情况,IP地址不同导致了页面跨域,具体原因大多是因为前端ifame问题 分析 ckeditor插件里config.js需要 ...
- Python实现doc转化pdf
Python实现doc转化pdf python源码实现doc转化pdf #-*- coding:utf-8 -*- # doc2pdf.py: python script to convert doc ...
- 【H5动画】谈谈canvas动画的闪烁问题
一般来说,在H5开发中,使用canvas往往只是为了展示一些简单的图表或者简单短小的动画,很少考虑到有闪烁的问题. 最近,在手机QQ魔法表情的项目中,就遇到了奇葩的闪烁问题. 这里说的闪烁,是指动画刚 ...
- 单片机成长之路(51基础篇) - 017 C51中data,idata,xdata,pdata的区别(转)
从数据存储类型来说,8051系列有片内.片外程序存储器,片内.片外数据存储器,片内程序存储器还分直接寻址区和间接寻址类型,分别对应code.data.xdata.idata以及根据51系列特点而设定的 ...
- JS前台效果
最新的在上面 2014年3月3日14:46:46 百分比思路 function fixWidth(percent) { return document.body.clientWidth * perce ...
- [转]MVC实用架构设计(三)——EF-Code First(3):使用T4模板生成相似代码
本文转自:http://www.cnblogs.com/guomingfeng/p/mvc-ef-t4.html 〇.目录 一.前言 二.工具准备 三.T4代码生成预热 (一) 单文件生成:Hello ...