Slowloris
Why don’t I use Apache for my web server? Is it because Nginx is newer than Apache? Is it because it handles concurrent connections “slightly better” than Apache? No, not really. I don’t even remember why I started using Nginx; I just did.
One thing I do know, however, is that there is a pretty funny denial of service (DoS) attack that can be done to Apache-based web servers from even a small Raspberry Pi. It is called a “slow and low DoS”, or simply “slowdos” or “slowloris”. It does not only affect Apache; Flask, a Python based web server, is also possible to attack in a similar manner.
You could watch Dr. Mike Pound’s Computerphile video about slowloris first. It probably makes everything a bit easier to understand.
I could just present the Python or JavaScript that does this, but I find it useful to understand how this vulnerability is allowed to exist.
How it works
The idea of the attack is relatively quite simple. You exploit the issues Apache has with serving many users at the same time. To understand why that is a problem, one has to understand how Apache in works and how it differs from Nginx.
Client requests are handled by three multi-process modules (MPMs). Administrators can thus swap out its connection handling architecture easily, if they so choose to. The MPMs are:
- mpm_prefork
- mpm_worker
- mpm_event
Which MPM one would use depends on what content you are serving. It also depends on what other modules you use with Apache. For example, mod_php cannot be used with mpm_worker which is an Apache module capable to parse and execute PHP code inside Apache itself, a common way to run PHP under Apache. The mpm_worker module is multi-threaded, in comparison to mpm_prefork, which makes it quicker to run on the server.
The slowloris attack exploit how Apache work by taking all the connections that are spawned by for example mpm_prefork or mpm_worker by sending incomplete requests. The connection will thus be open and after a while maxing out the maximum connections allowed. This will result in a DoS.
In comparison to Apache, Nginx is newer (1995 and 2002 respectively). The sole reason why Nginx exist is to solve the C10K problem, which is the problem of how to optimise network sockets in order to handle a large number of clients at the same time. We have to appreciate the fact that Apache was made in an era where most had no idea how big and powerful the internet were going to be.
Thus, it is very unlikely to slowdos a Nginx based server as it is made to handle a lot of concurrent connections. Apache on the other hand, will often yield under the high pressure from such an attack.
How to prevent it
I could say “just use Nginx”, and I was planning to do so as well, but then I would not be totally honest. Slowdos attacks can actually be used on some versions of Nginx (up to v1.5.9) or badly configured Nginx for that matter, but in practice it is unlikely. Thus, saying “just use Nginx” is valid. However, for a developer that is dependent and accustomed to Apache, it is possible to for example use Nginx and Apache together for example as using Nginx as a reverse proxy.
There are also Apache modules to mitigate the attack, namely the modules: mod_limitipconn, mod_qos, mod_evasive, mod security, mod_noloris, and mod_antiloris. Since Apache 2.2.15, Apache ships the module mod_reqtimeout as the official solution.
It is also possible to use mpm_event module. While the mpm_worker needs 1,000 threads to sustain 1,000 concurrent connections, mpm_event may get by with 100 active threads and 900 idle connections managed in the event queue. The mpm_event will use a fraction of the resources of the mpm_worker in that scenario, but the downside to this: each of those requests is handled by a separate thread which must be scheduled by the kernel and as such will incur the cost of switching context.
Nginx, on the other hand, uses the event model itself as its scheduler. Nginx processes as much work on each connection as it can before move on to the next one. Thus, no extra context switching is required.
How to exploit it
It is really simple. Run this python code or this JavaScript code found on GitHub. You can set up this attack against a webserver on a Raspberry Pi and just put it somewhere and forget about it.
Please do not DoS people. Contrary to popular belief, writing in PHP does not make a person fair game.