Increasingly, Pentest clients are developing and operating cloud-based software-as-a-service applications that service multiple organisations.
The Heightened Risk of Cloud Applications
This creates a risk that is largely absent from on-premises solutions – the risk of cross-tenant attacks, where one organisation on a cloud platform conducts a lateral attack against another organisation.
Vulnerabilities that allow such attacks are often critical, placing both the cloud provider and their clients at imminent risk, and requiring urgent remedial action. One reason for this is that most cloud platforms allow anyone to sign up as a new organisation. So, while cross-tenant attacks often require authentication, the risk profile is more comparable to an unauthenticated attack.
Pentest’s experience with modern applications is that most – but not all – have strong perimeter security. It’s rare that an unauthenticated attacker is able to exploit a high-impact vulnerability. What is far more common is privilege escalation flaws – where an authorised, but low-privilege user, is able to escalate their privileges or target other users.
The reason for this is a concept called “attack surface”. Modern development frameworks are designed to limit what is exposed to unauthenticated users – just a hardened authentication system. The attack surface is limited – there are few opportunities for malicious users to attack. However, once a user is authenticated, a large amount of application functionality is exposed – a large attack surface. There are many opportunities to inject malicious payloads or to bypass access control policies – and an application has to defend every single one of these.
All these considerations put SaaS applications at high risk of attack – a large attack surface is exposed, and the impact of weaknesses can be severe. And these risks remain, despite high-grade encryption, despite advanced application firewalls and despite strong security operations and governance. Even with all those defences, a single coding error in a single line of the application can put the entire userbase at risk.
Creating a Secure Application Architecture
Because of these risks, there is a desire to architect applications in a way that mitigates cross-tenant attacks, and there are a few approaches to do so.
The highest level of segregation is achieved by running separate application instances for each tenant. Each organisation has its own private network, with dedicated instances of web servers, databases and other support infrastructure running within this. An attack on one application instance is contained within that instance, and the use of network segregation makes lateral escalation very difficult, if not impossible.
But this comes at a cost – all these instances are expensive to operate. It’s not just cloud provider fees, there’s the staffing costs of the teams needed to manage these systems. This architecture is suitable for some environments – particularly when there are a modest number of tenants, each serving a large user base. But for web scale deployments, where there will be many thousands of tenants, this is intractable.
At the other end of the scale, applications can utilise fully shared infrastructure – where every tenant is on the same cluster of web servers, databases, etc. In this case, tenants are segregated by application logic alone. This carries the risk alluded to earlier: it only takes one failure within the application logic to create a critical security flaw.
So, with both fully segregated, and fully shared architectures being undesirable for different reasons, is there a compromise that can get the best of both worlds?
Achieving an Effective Compromise
An architecture Pentest are increasingly seeing is the use of shared infrastructure with per-tenant databases. All the tenants share the same web servers, support infrastructure, and database servers. But on the database servers, a separate database instance is created for each tenant. Modern databases can scale to thousands of database instances without issue, so this architecture is cost comparable with a fully shared architecture.
At an application level, the database connection pool needs to coordinate with the authentication system. The authentication system itself can access any tenant’s database – but this is a small attack surface that can be carefully hardened. Once a user is authenticated, application code has access only to a database connection for the tenant corresponding to the authenticated user. This means that any data-based attacks are restricted to that one tenant.
Common vulnerabilities, like missing authorisation checks, stored cross-site scripting, and SQL injection – all have their impact restricted. Of course, such vulnerabilities still carry risk and need to be mitigated. But because they are contained within a tenant, and only exploitable by authorised users within that tenant, they would rarely have a critical risk rating.
Understanding the Limits
There are certain attacks this architecture does not defend against. In particular, any kind of remote code execution attack would have a cross-tenant impact. However, such vulnerabilities are quite rare in modern applications. Certainly, much rarer than missing authorisation checks or cross-site scripting.
Overall, while this architecture does not solve everything, Pentest feel that it is a valuable security improvement that comes at relatively little cost and is advisable for most SaaS applications.