Versão original em português disponível
This is part of a collection of posts about software security through the development and operation process (DevSecOps). The vulnerability covered in this article is denial of service by exploiting heavy requests payloads.
Denial of Service, or just DoS (a.k.a. DDoS), consists in several exploiting techniques that weaken your service, aiming to find security breaches along the maintenance window, make your service unavailable or simply raise your infrastructure costs, even the system not being impacted.
OWASP1 considered this exploit the fourth most popular in terms of API security breaches, in 2019.
Once during the homologation phase for a brazilian information security label for e-commerces (SiteBlindado), I encountered a warning that some system operations were vulnerable to receive a much more larger data traffic than really needed. Then I had to setup specific requests payload size limits and it turns out to be a good DoS protection.
How to identify a heavy payload DoS
The most effective way to identify this attack situation is analyzing the requests size incoming to your servers. This information generally is available in access log formatters (e.g: nginx uses the variable $request_length). A common traffic log would be:
2020-06-05T10:14:02Z GET / 1.1.1.1 459 "Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0"
2020-06-05T10:15:23Z GET /products 2.2.2.2 257 "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1"
2020-06-05T10:16:53Z POST /admin 3.3.3.3 523 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:17:20Z GET / 4.4.4.4 289 "Mozilla/5.0 (Android 4.4.2; Tablet; rv:65.0) Gecko/65.0 Firefox/65.0"
2020-06-05T10:18:22Z GET / 5.5.5.5 336 "Mozilla/5.0 (Android 4.4.2; Tablet; rv:65.0) Gecko/65.0 Firefox/65.0"
2020-06-05T10:19:11Z GET /products 318 6.6.6.6 "Mozilla/5.0 (Linux; U; Android 5.0.2; en-US; XT1068 Build/LXB22.46-28) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.10.2.1164 Mobile Safari/537.36"
The most important piece of information in this case is the number between the client IP address and the User Agent header value. For example, in the third request, this number is 523. This is the request total length in bytes, including header and body.
If your service is under attack with heavy requests payloads, you'll notice a huge difference between the normal requests length and what you are receiving during the attack attempt. That's why is important to know the common traffic limits of your software. Ordinarily, what's the average size of your requests?. If you're being attacked, it would exist an increase on third request above (normally these attacks use your resources with data post, such as an image upload or data form):
2020-06-05T10:16:53Z POST /admin 3.3.3.3 9000000 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
At this new log sample, we had an increase in the request's total length, from ~0.5kb up to 9mb! Mostly this symptom comes together with high throughput of the same heavy request, like this hypothetical log situation:
2020-06-05T10:14:02Z GET / 1.1.1.1 459 "Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0"
2020-06-05T10:15:23Z GET /products 2.2.2.2 257 "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1"
2020-06-05T10:16:53Z POST /admin 3.3.3.3 9000000 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:17:20Z GET / 4.4.4.4 289 "Mozilla/5.0 (Android 4.4.2; Tablet; rv:65.0) Gecko/65.0 Firefox/65.0"
2020-06-05T10:18:22Z GET / 5.5.5.5 336 "Mozilla/5.0 (Android 4.4.2; Tablet; rv:65.0) Gecko/65.0 Firefox/65.0"
2020-06-05T10:18:53Z POST /admin 3.3.3.3 9000000 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:18:53Z POST /admin 3.3.3.3 9000000 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:18:53Z POST /admin 3.3.3.3 9000000 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:18:53Z POST /admin 3.3.3.3 9000000 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:18:53Z POST /admin 3.3.3.3 9000000 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:18:53Z POST /admin 3.3.3.3 9000000 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:18:53Z POST /admin 3.3.3.3 9000000 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:19:11Z GET /products 318 6.6.6.6 "Mozilla/5.0 (Linux; U; Android 5.0.2; en-US; XT1068 Build/LXB22.46-28) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.10.2.1164 Mobile Safari/537.36"
Something is wrong with this considerable size and throughput increase. It's time to act!
Rightly configuring your server limits
The solution to mitigate this exploit is to establish hard limits to your requests size, avoiding your servers to unnecessarily work on heavy requests that exceeds the acceptable traffic to your system's common operation.
You can set these hard limits from "outside in", from your cloud application firewalls (like AWS WAF, CloudFlare WAF and Akamai Web Protector) to your reverse proxy or application servers. The great majority of servers provide an option to limit the maximum length of incoming requests. I'll list a few, from different architecture layers:
- Limiting at the firewall;
- Limiting at reverse proxy or load balancer;
- Limiting at application server;
- Limiting at application code;
Conclusions
- Regularly monitor your application and your servers;
- Know your application common limits and traffic;
- If you're receiving an attack attempt, being aware of your common traffic average size will make your life much easier on identifying the resource under attack.
- Adopt the philosophy of "limiting down until necessary";
- Set low limits to ALL of your requests sizes (you can establish an average size based on your entrypoints with larger traffics).
- Raise these limits in a granular, specific and on-demand way (e.g: if you need a file upload, adjust the configuration to allow a higher request limit specifically to this upload operation).
Top comments (0)