Applications are your business. Your customers see more value every time engineers push code. And that’s why your engineers are continuously empowered to move faster.
But, with all these changes in production, your application security posture is morphing.
Enter the application security team. They exert a massive amount of effort on risk remediation. And now, you’re asking yourself questions like:
- What percentage of our effort genuinely reduces our application risk?
- How can we validate our production risk is decreasing?
- Are we reducing our risks faster than engineering is introducing new concerns?
Many security teams struggle to answer those questions. In this blog, we’ll discuss the key components of an application’s security posture and introduce some ways to calculate your organization’s overall risk.
Application Security Posture Components
To use an analogy, if you think about software security as a Greek temple, the security posture is the roof. The pillars supporting that roof are the components that lead to data breaches.
Weakness in a single pillar doesn’t result in the roof collapsing, but as weaknesses expand to other pillars, there is an exponentially higher chance of catastrophe. Those pillars are all anchored in the application’s architecture. So, when the architecture has flaws, it’s a recipe for disaster.
One of our previous blogs dives into the complexity of modern applications if you’d like additional insight.
Threat Type and Severity
Theoretically, if software has no threats, there are no entry points for hackers to exploit. And since discovering these threats is the first step, this skillset is invaluable. In fact, LinkedIn has over 40,000 security researcher jobs posted.
The most commonly examined threat types are vulnerabilities. Here are the frequently used vulnerability acronyms you need to know:
- Common Weakness Enumeration (CWE) encompasses all known software and hardware exploits. Every exploitable aspect of computing is a CWE.
- Common Vulnerabilities and Exposures (CVE) are all software packages known to be at risk. This list continuously grows as security researchers discover new exploits.
- Common Vulnerability Scoring System (CVSS) values demonstrate how easily a package can be hacked. The scores range from 1-10, with high numbers indicating increased exploitability.
However, it’s also crucial to look for threats in the form of:
- Unauthenticated and unauthorized APIs
- Hardcoded or reused credentials
- Secrets in code
- Web application vulnerabilities (injection, server-side request forgery, etc.)
Traditionally, application security tools provide a siloed risk score for each threat without context from the other pillars.
Exploitability
Software components are exploitable if a bad actor can reach them. According to Gartner, the growth of attack surfaces is the largest risk to organizations.
Relying on firewalls, VPCs, IP allow lists, and other infrastructure-centered security measures don’t always prevent software from being exposed to the outside world, hence the popularity of the zero-trust model.
Let’s dive into the factors determining exploitability:
- Internet-facing services are directly exposed to the internet.
- Third-party services communicate with external systems.
- APIs are endpoints designated for software communication.
- Unencrypted communication paths are accessible via packet sniffing and man-in-the-middle attacks.
Attack surfaces are entry points for hackers, so teams must always know where these software entry points exist.
Business Criticality (Data Sensitivity)
Every modern company is in the data business. And, it’s no secret that the most valuable data is sensitive data.
Accidentally exposing data to the outside world comes at a price. In fact, the top 12 data breaches, as of Dec. 2022, amount to over $4.4 billion in fines. Clearly, it’s business critical to understand where sensitive data lives in your software and how to protect it.
There are three protected data types: Personally Identifiable Information (PII), Protected Health Information (PHI), and data subject to the Payment Card Industry Data Security Standard (PCI-DSS). And, since 49% of data breaches target the payment card industry, organizations that make apps connecting to these sensitive data types should be extra diligent about their security.
Many teams rely on manual tagging or data classification tools to understand where sensitive data resides in software. One added complication is that not every table in a schema or database will be sensitive, so specific APIs are inherently more dangerous than others.
Adding to the data protection concerns, environment variables are frequently used to point to production databases. Mistakes in environment variables can lead to PII being stored in non-production environments (QA, Dev, etc.), which is a GDPR violation.
Protecting your business and customers requires an accurate inventory of where sensitive information is stored across your software ecosystem.
Architectural Context
We’ve covered the three main pillars of an application’s security posture. Now, let’s dive into the foundation of security: Architectural Context.
The architectural context is the most critical factor in an application’s security posture. Consider these two scenarios.
The first microservice:
- Imports an open source library with a high CVE whose CVSS score is 8.2
- Is not internet-facing and is deployed on-premise within a VPC whose IP allow list restricts outsiders
- Doesn’t connect to any services (or databases) with sensitive data
- Will deploy to production
The second microservice:
- Imports an open source library with a medium CVE whose CVSS score is 5.6
- Exposes three APIs to the public internet
- Accesses a database containing patient healthcare records
- Will deploy to production
Now, ask yourself:
- Am I required to fix either of these services with my current Service Level Agreement?
- How will each of these services affect our application risk?
- Should we halt the deployment of either of these microservices?
Considering the architecture surrounding these services, it’s intuitive that the second microservice has a more significant impact on the overall security posture. However, for many organizations, the second microservice is more likely to be deployed since its only known CVE is “medium risk.”
This example demonstrates why, in the world of Continuous Delivery, it’s crucial to understand the entire risk introduced by code releases. Architecture visibility is fundamental to maintaining a safe application risk posture.
Security Posture Equations
Here, we’ll cover a possible approach to calculating security posture. These calculations will vary greatly by organization, so this section intends to be inspirational for security teams.
Service Risk Posture
A good first step is determining the risk levels of each service in an application. In the application context, a service is a deployed component that accomplishes a specific function. Some examples include a:
- Microservice
- Database
- Message Broker
- 3rd Party Connection
To weigh the Threats, Exploitability, and Criticality of each service, we can use the following equations:
(1)
Riskservice = Threats * Exploitability * Criticality
(2a)
Threats = Max(CVE) + A[IsAPIunsecured] + WebAppVuln + B[IsUnencrypted]
(2b)
Exploitability = C[IsConnectInternet] + D[IsConnectThirdParty] + E[IsConnectInternal] + F[IsUnencrypted]
(2c)
Criticality = PipelineStage + G[IsSensitive]
By substituting (2a), (2b), and (2c) into (1), you can calculate the security posture for an individual service. The variables are defined in the following table.
Variable | Definition | Possible Value |
A | Const: Add weight to unsecured APIs | 10 |
B | Const: Add weight to unencrypted communication (for establishing a threat) | 5 |
C | Const: Add weight to internet-facing connections | 5 |
D | Const: Add weight to third-party connections | 3 |
E | Const: Add weight to internal connections | 1 |
F | Const: Add weight to unencrypted communication (for establishing an exploitation path) | 7 |
G | Const: Add weight to sensitive data connection | 10 |
Max(CVE) | Float: The maximum CVE score in the service’s library dependencies | 0 to 10.0 |
IsAPIunsecured | Bool: An unauthenticated/unauthorized API exists | 0 or 1 |
WebAppVuln | Float: The maximum risk score associated with detected web application vulnerabilities (e.g., SQLi) | 0 to 10.0 |
IsUnencrypted | Bool: Uses unencrypted communication (e.g., HTTP via port 80) | 0 or 1 |
IsConnectInternet | Bool: The service has a public-facing IP address | 0 or 1 |
IsConnectThirdParty | Bool: The service connects to a third-party | 0 or 1 |
IsConnectInternal | Bool: The service connects to an internal service | 0 or 1 |
PipelineStage | Float: Add weight to the environment (e.g., Dev, QA, Staging, Production) | 0.1 to 1.0 |
IsSensitive | Bool: The service accesses sensitive data (e.g., PII, PCI, PHI) | 0 or 1 |
Application Risk Posture
Next, we can calculate the risk of entire applications. Because application architectures vary from complete monoliths to strictly microservices (and anywhere between), a single high-risk service indicates substantial risk.
One prioritization method is:
- Calculate the highest-risk service in the application.
- Subjectively determine the business significance from stakeholder input.
- Find the number of critical risk services.
(3)
Riskapplication = Max(Riskservice) * BusinessSignificance * QuantityCriticalRisks
Example Calculations
Let’s revisit the microservice comparison scenario from earlier in this blog using these equations.
Service Risk Posture Example
Plugging in the information about the first microservice yields the following.
Riskservice = Max(CVE) * E[IsConnectInternal] * PipelineStage
Riskservice = 8.2 * 1 * 1.0
Riskservice = 8.2
Understanding the business context of this service allows us to see that it doesn’t have a significant effect on our risk posture.
We see a more substantial result when we analyze the second microservice.
Riskservice = Max(CVE) * (C[IsConnectInternet] + E[IsConnectInternal]) * (PipelineStage + G[IsSensitive])
Riskservice = 5.6 * (5+1) * (2)
Riskservice = 67.2
Initially, the CVSS scores indicated that service 1 is higher risk. However, once we factor in the surrounding architecture, we see that service 2 has a much greater effect on our overall risk posture.
Application Risk Posture Example
To determine the overall risk of an example application, let’s assume we’ve already calculated the risk posture of several more services. In this example:
- The array of risk scores is [8.2, 67.2, 21.9, 0.02, 14.0], with 67.2 being the maximum.
- The business significance is subjectively given the value of 4 (with 10 being the highest).
- The “critical risk” threshold is 50, so only one of these risks is critical
In that case, our total risk is calculated as follows.
Riskapplication = 67.2 * 4 * 1
Riskapplication = 268.8
From here, we’d want to determine the risk of the other services and applications in our ecosystem. Then, we could systematically prioritize the largest risks to our organization.
Conclusion
Today, we introduced the concept of calculating your application security posture. If you want to learn more about how Bionic continuously prioritizes risks in production, contact our team today.