Cloudflare DDoS Protection. Protect direct access to your server with hidden headers

DDoS attacks or automated robots seeking to “steal” information from large sites (without intending a DDoS although they may cause one) have always been a problem since the WWW existed but in recent years it is taking a very relevant role. Proxy service providers with millions of available IPs at very competitive prices mean that anyone, without being a hacker with an infinite number of compromised computers at their disposal, can enjoy an important pool of IPs and can cause a real problem to any web server.

In one of the projects I am involved in I had to develop a robot to scrape Google Shopping, Amazon and hundreds of other e-commerce sites. Equally as a systems administrator for other clients I have had to face the way to stop crawling and DDoS attacks, so I know perfectly both sides of the coin and the challenges involved in each case. And it is honestly fun, the cat and mouse game.

There are countless measures, from honeypots, JavaScript challenges, request limiting by IP or IP range, IP blacklist blocking, traffic analysis and selective blocking by type, blocking logic by behavioral pattern in the application, secret cookies and an infinite etcetera with which both players of the game will have to deal and obviously all of this raises the cost of site maintenance, its resources and the resources and time required by the attacker.

Generally I always favor implementing all services and tools autonomously, from my own server and without depending on third parties. But in this case, given the magnitude of the problem and the eventual need for large resources it is interesting to rely on companies specialized in this task such as CloudFlare or Sucuri, the former being more specialized in DDoS protection and network optimization and the latter in WAF protection, both ultimately converging in their services but that would make for another post. In this one we will focus on the use of CloudFlare (hereafter CF) and its DDoS protection.

Among the multiple interesting functionalities of CF is the degree of security and protection of the site, ranging from none, low to “I’m under Attack!” mode. This last one is very effective using a JavaScript challenge with cookies without user interaction, I know I could do this myself on my server but robot programmers know how to study even JavaScript challenges and bypass them so it would be a never-ending job so for the price of CF (even the free version includes this functionality) it is worth it and they take care with their large infrastructure and resources of making it very difficult for robots to bypass the measures.

Unfortunately (remember the cat and mouse game) laws are made to be broken and the simplest way to avoid this protection along with the multiple security measures implemented by CF is simply to bypass it. And it is usually quite simple, there are multiple methods to find out the real IP on which the original web server without CF protection is hosted and once you have the IP you can configure robots to use it directly ignoring the proxy IPs offered by CF’s DNS. In an ideal world you could find ways to make finding the real IP very difficult but it would require continuous effort and caution from the entire team, both systems and development, and the latter tend to pay little attention to IP, protocol and security problems so as far as possible, as system administrators it is interesting to be able to count on methods to remedy the possibility that an attacker knows the real IP.

Recently CF has announced the ability to modify and add specific headers to the request it sends from its proxies to our server. Before it could be done, but it was necessary to program CF’s “workers”, now it is much simpler (https://blog.cloudflare.com/transform-http-request-headers/). This simple tool opens up a wide world of possibilities.

The simplest way to prevent direct access to the web server would be to block at the IP level any IP that wants to access ports 80 and 443 that is not within CF’s IP range (https://www.cloudflare.com/ips/). The problem with this solution is that if you have several domains hosted on the same server/IP and not all domains are protected by CF then you cannot block by IP. Equally, although CF’s IP range does not change very often, it forces you to keep an eye on any updates to their IP range to adapt it to your firewall rules.

So we need a method that is easier to maintain and useful for a more complex system. And this is where CF’s custom headers come into play. The idea is simple, create a header with a key value and verify on the server if this header has been sent in the request, if the header has not been sent then we can be sure the connection is direct without going through CF. In principle, the header would be very difficult to find, only whoever configured it knows it, the web server and CF. To find the hidden header it would be necessary to hack the web server and execute some script on it that would show the headers sent in the request through CF, something possible but even in that case the attacker would have to know what they are looking for and what method the server is using to deny direct access. Is the method perfect? Sure not, but it is one more part in the cat and mouse game. Anti-DDoS protection goes much further but a complete analysis of all possible techniques is not the objective of this post.

As a concrete example I detail how to apply the header filter on the nginx server, along the way we can take the opportunity to add more header checks such as CF geolocation (free pro geolocation).

To verify the hidden header, simply add the following in the nginx “server” section (obviously you first had to create said header in CF as explained in the link I left you):

if ($http_customheader != 'SECRETTOKEN') { return 511; }

And that simple, any direct request that arrives at the server without specifying the customheader with the value SECRETTOKEN will receive a nice 511 error as a gift. As the return value you can choose whatever you prefer following logical criteria (do not do a return 200). In this case I used 511 (Network Authentication Required) to thus have a record in the logs of the direct access attempts that have occurred in an informative way (always keep an eye on logs).

Another interesting verification would be access control by country. One of my clients was suffering countless attacks from practically every country in the world (part of the DDoS game) but their potential market was only a few countries so thanks to CF’s geolocation header plus direct access blocking it is easy:

We add in nginx’s http block:

map $http_cf_ipcountry $countryok {
default "0";
"FR" "1";
"ES" "1";
"DE" "1";
"BE" "1";
"US" "1";
}

We add in nginx’s server block:

if ($countryok != '1') { return 511; }

As you can see I use the cf_ipcountry header to obtain the ISO country code and verify if it is in the allowed list.

The possibilities are endless, you just have to apply imagination.

I hope it is useful and if you need technical advice to implement DDoS protections I can offer you as a service my years of experience in this field.

Leave a Comment

Este formulario guarda los datos que indiques de nombre, email y comentario para poder realizar un seguimiento de los comentarios dejados en cada entrada.