Introduction
As explained in the WiKi, slow HTTP attacks rely on the fact that the HTTP protocol, by design, requires requests to be completely received by the server before they are processed. If an HTTP request is not complete, or if the transfer rate is very low, the server keeps its resources busy waiting for the rest of the data. If the server keeps too many resources busy, this creates a denial of service. [Source : https://github.com/shekyan/slowhttptest/wiki ]
Slow HTTP attacks are primarily of three types.
- Slow headers (a.k.a Slowloris)
This attack works by opening a large number of connections with the web server and keeping them alive by slowing sending never ending headers. The server won’t close the connections as the request is not complete and it will eventually exhaust all the resources on the server, blocking the legitimate requests. - Slow body (a.k.a R-U-Dead-Yet)
R-U-Dead-Yet works just like Slowloris, but instead of sending never ending headers, it sends never ending POST body, forcing the server to keep the connections open. When all the resources of the server are occupied, it is unable to serve the legitimate requests. - Slow read
The above-mentioned attacks exploit a web server by sending slow requests, however, slow read exploit is based on reading responses from a server very slowly. It works by advertising a very low client receive buffer size, triggering a big response from the server, and taking up to minutes to read a single response. When multiple such connections are created concurrently, it can consume all the server resources and lead to DoS. It can’t be explained better than the author of this attack himself in this post.Nginx architecture
Nginx has a master process and a number of helper processes (including worker processes). Master process manages all the privileged operations whereas the worker processes do the actual work and handle the connections. Nginx’s architecture is fundamentally different from that of Apache’s. Apache spawns a blocking thread for every new connection, whereas Nginx is based on non-blocking event-driven architecture.
The diagram below summarises the flow:
This architecture provides innate prevention against Slow HTTP attacks to some extent as the worker process is not blocked on IO. It can continue to serve other requests. However, it is not full proof and depends on the Nginx configuration options as well.
Some of the common configuration options provided by Nginx to prevent such attacks are:
1) limit_req – to limit the rate of requests from one IP
2) limit_conn – to limit the number of connections from one IP
3) client_body_timeout – to close the connections with slow body
4) client_header_timeout – to close the connections with slow headers
5) send_timeout – If the client does not receive anything within this time, the connection is closed.
Conclusion
Slow HTTP attacks can be as vicious as volumetric DDoS attacks, if not dealt properly. Moreover, there are a lot of moving parts in the Nginx configuration and we need to understand them properly before making random copy/paste changes.
I also see one more fix to this problem by rejecting very low client-side receive buffer window sizes, but I’m yet to explore that path.
References
1) SlowHTTPTest
2) Are you ready for slow reading
3) Inside Nginx
4) Nginx reference
5) Nginx DDOS mitigation