When it comes to breaches involving apps and data exposure, fingers are almost always pointed at developers. Many times, this is the right direction. Injection attacks and stack-based exploits are almost always the result of insecure code. Usually because Security Rule Zero was violated.
But we can't blame all breaches on developers. The truth is that even if developers could turn out perfectly secure code, you still need application services to protect against many other attacks.
That's because application security is a stack. There are attacks that exploit protocols and networking principles that cannot be simply "secure coded" away. Further complicating security is that these attacks are often undetectable by applications because they lack the visibility to distinguish malicious from legitimate requests.
In particular, there are three attacks that developers simply shouldn't be responsible for handling. Instead, these attacks are best detected and mitigated by application services deployed upstream, where visibility and context are available to help put a stop to them.
We use the term volumetric to describe a traditional distributed denial of service attack to distinguish the network overload-based attacks from those that have moved "up the stack" to attack the application layer. They are different classes of attacks and thus we need to be able to defend against both of them, but the way in which we do so takes very different solutions.
A volumetric attack is just a blitz. A barrage of traffic is directed at a particular service with the intention of overwhelming whatever device/infrastructure/software is handling requests. The principle in play is that all devices - whether hardware or software, on-premises or in the cloud - have limited resources. Thus, by sending enough requests the device can be overwhelmed and shut down access to everything behind it.
The reason developers cannot effectively prevent this attack is because applications rely on platforms and host operating systems to manage networking. A volumetric DDoS attack targets that network stack and is able to consume so much of the shared resources that the application is barely able to process requests in order to determine it is under attack.
Secure coding can't prevent this - it's not an exploit due to a vulnerability. And it's really not the fault of code in any part of the system. It's simply the case that no matter how hard we try to pretend there is no hardware, that's where resources come from and they are limited.
Volumetric DDoS attacks are best detected and mitigated by high-capacity, high-performance application services residing up-stream from an application. The closer to the source of the attack, the better.
No exploit, no secure coding solution.
Moving up the stack to the application layer we find an insidious form of denial of service called Layer 7 (or HTTP) DDoS. These attacks are infuriating because they are exploits, but they are not due to a vulnerability or insecure coding. These attacks work because of the nature of HTTP and the systems that implement it.
There are generally two types of layer 7 DDoS attacks: slow and fast. Slow layer 7 DDoS consumes resources by pretending to have a terrible network connection and s l o w l y siphoning off responses from legitimate requests. This consumes resources because web apps are connection-based, and once again resources to maintain those connections are limited. By connecting with enough clients and making legitimate requests only to slowly receive responses, attackers are able to tie up application resources. This has the effect of making it nearly impossible for legitimate clients to connect, effectively carrying out a denial of service attack.
This attack is particularly nefarious and difficult to detect - unless you're comparing network speeds to receiving speeds. That is, application services up-stream have visibility into the network characteristics of clients and can more accurately determine whether those clients are purposefully being slow to receive or really have a network issue. Determining legitimacy is critical to shutting down these kinds of attack.
Basically, these attacks exploit at the protocol layer (HTTP) and there is nothing that secure coding can do to address it.
No vulnerability, no secure coding solution.
Last but not least is credential stuffing. The unbelievable number of credentials exposed through breaches in the past few years makes this attack a significant one to defend against.
Credential stuffing attacks generally rely on bots or tools, because they're based on brute force principles that take advantage of the vast pools of existing username/password dumps. Rarely are you going to find credential stuffing attacks carried out manually. A successful credential stuffing attack is not the result of insecure coding*. Attackers are not trying to exploit anything but poor password practices and the inability to recognize an attack in progress.
To detect these attacks, you need to be able to determine that the client is not a valid human being. So in a sort of reverse Turing test, you'll need to present challenges and use CAPTCHAs in ways that these automated systems are not able to answer.
No amount of secure coding can prevent this attack from succeeding. Improving password practices and detecting attack attempts are the best ways to avoid succumbing to this growing scourge of the Internet.
No exploitable code, no secure coding solution.
*Credential stuffing attacks may be made possible by insecure coding. After all, a significant number of breaches occur because of code-based vulnerabilities that result in massive lists of credentials available for this attack.
It's important to recognize when secure coding can be used to prevent an attack and when it can't. It's important because we can't just keep pointing the finger at developers for every successful attack. Security needs system-level thinking; we need multiple solutions because there are multiple types of attacks we need to defend against.
It's important to differentiate in order to effectively and successfully defend against the variety of attacks most organizations will be subjected to in the near future. Don't waste time trying to force developers to defend against attacks when it's (1) not an exploit due to insecure coding or (2) not possible due to a lack of visibility.
We need to approach security strategically from a system of services that provide the right security at the right places no matter what the source or attack surface might be.