Most of you reading this are responsible for the delivery and security of hundreds of applications. Those applications can be further broken down into thousands of workloads. Some workloads are responsible for data, others for managing identity, and still, others present an API to machine and human users.
Applications have grown increasingly complex since the early days of “all in one” monolithic architectures. The client-server architecture gave us two distinct workloads, each with a specific focus. The three-tier gave us three distinct workloads, breaking down applications even further.
Mobile applications added another workload – and sometimes two. Now we're adopting microservices (container-native), and the resulting explosion in workloads is nothing short of overwhelming. Applications are glued together through integration, using APIs and other connective tissue to enable communication.
But wait! There's more. Let's not forget that digital services are merely applications glued together through orchestration, a clever technology trick that makes an experience appear seamless when it's really held together by APIs and message queues.
Applications today are a sophisticated set of workloads, applications, integration methods, and middleware that somehow manage to present a slick user interface that delights customers and encourages engagement.
It’s no wonder that securing “applications” is harder today than it has ever been. We aren’t just securing applications; we’re securing everything that means:
- Communication (protocols)
I’ll stop with this incomplete list. There’s more than enough here to keep us all busy until our grandchildren take over responsibility for security.
Attackers recognize the opportunities in today’s complexity. They have a veritable smorgasbord of options from which to plan and execute an attack.
While many security pundits like to raise the red flag at container-native application architectures and note just how many attack vectors these loosely-coupled, software-driven applications are, the fact is that their complexity is just another brick in the much bigger, already complex, wall that security professionals are constantly banging their heads against.
When the task before you appears impossible, it’s a good time to take a step back and try to see the problem from a new perspective.
I’m a fan of the perspective my colleague Dan Woods has on this topic. He makes a clear distinction between two discrete types of vulnerabilities: inherent and inadvertent.
Inadvertent vulnerabilities are those caused by human mistakes. They include misconfigurations, insecure coding practices, choosing speed over security, and removing protections in production to meet a deadline. These often wind up as a CVE and cause a splash on social media.
These vulnerabilities can be addressed - no matter the application architecture or environment - by employing practices that stretch security to envelop the entire application lifecycle. Introduce scans, reviews, and gates earlier in development. But don’t ignore that these vulnerabilities can also be uncovered by regular scans and tests in production and should be immediately addressed. Don't just shift security; stretch it.
Inherent vulnerabilities, however, are a different matter. These are vulnerabilities to protocol and logic abuse, vulnerability to attack of services you must provide because there's no other option. DNS, for example, must be public and is often the target of attacks. Not because the implementation (code) has vulnerabilities, but because of its critical role in delivering applications.
Credential stuffing, too, is an inherent vulnerability – and will remain so until we figure out a new way to establish identity. You can’t not offer a way to "log in" to a service, so you can't avoid a credential stuffing attack.
Inherent vulnerabilities often require an external solution or workaround, as is the case with protocol-based exploits such as HTTP floods and DNS amplification attacks.
Neither of these types of vulnerabilities is a direct result of modern application architectures or multi-cloud environments. They are made more prevalent and sometimes more likely, but ultimately these two types of vulnerabilities have always existed and are likely to continue to exist.
Divide and conquer
Breaking down complex problems into smaller, more manageable tasks can be an effective way to approach such a significant effort. This approach has been called “divide and conquer” and often falls under the umbrella of an “analytical approach.” In either case, it’s a strategy that calls for simplification to help focus limited resources in the most effective way possible.
If you start by putting vulnerabilities into two buckets – inherent and inadvertent – you can build out a security practice that better enables everyone to determine what the best and most effective mitigation is going to be. After all, secure coding isn’t going to stop credential stuffing, and yet another CAPTCHA isn’t going to stop an attacker from exploiting insecure code.
To manage complexity, don’t get mired in the details of a specific vulnerability. Yes, you must address it, but if you can then step back and establish security practices that address each of the two types of vulnerabilities, you’ll go a long way toward simplifying security.