Any set of security controls deployed in your infrastructure may fail. Given enough pressure, some controls will certainly fail. No surprises here, but the question is – how to build our systems to make security incidents less damaging in case of a failure of some components? How to prevent data leaks even in case of a successful data breach?
Building security tools, we strive towards defense in depth approach. Meaning, we provide sufficient opportunities for building security for the whole data lifecycle – as opposed to implementing some singular security function.
That’s what defense in depth is – an independent, yet interconnected, set of security controls aimed at mitigating multiple risks in case of an attacker crossing the perimeter.
Let’s observe the evolution of security controls of a typical web application from “band-aid” security to defense in depth pattern.
Typical web app architecture and potential attacks
For a better representation of this concept, let’s consider the architecture of a typical web application, in a non-typical representation:
This is an oversimplified architecture, but it’ll help us see the dataflow:
the data is gathered on web frontend,
processed on backend, and
stored in a database.
The database is the final destination where the data is stored at rest (in a real world, there could be many microservices, many databases and datastores, multiple cache levels, ad nauseam, but they all fall into the same pattern).
In a typical security design model, the hostiles are only on the outside. On paper, they’d need to pass through the frontend and backend to get to the database. There are dozens of attacks aimed at each component.
In an unfortunate (but typical) outcome resulting in a successful attack, an SQL injection gets inside of the database where it moves through all the layers and grabs all the necessary data in a single shot.
But in the real world, many attacks occur because of insiders (75% of security threats arise through inside treats, according to cold hard statistics). So when designing an app’s architecture, we should take into account all risks, including with the risk of an inside job from an attacker with arbitrary access to any of these layers.
Band-aid security model
Let’s take another look at our infrastructure with the typical security controls in place.
There is a whole array of security controls for data at the disposal of security-conscious web-apps:
Means of active protection, i.e. firewalls, WAF, IDS;
Access control, authentication, roles, access restrictions for database and backend servers, proper data schemes and access policies;
Data protection – TLS everywhere and database/storage level encryption;
Secure coding practices, input validation and proper dependency management (to decrease the number of potential vulnerabilities in node modules).
And of course, app behaviour and data access are logged, monitored, and there’s somebody to keep an eye on alerts.
Unfortunately, all these measures are merely a “checklist” protection or “band-aid” security, as we call it. Developers typically think about security measures as about a set of perimeters and believe that the more perimeters, the better. However, attackers think in graphs trying to construct an “attack graph” looking for vulnerabilities in each perimeter. Eventually, attackers will find vulnerabilities in every security control, combine them into an “attack graph”, and get to the data.
At first glance, this infrastructure looks very safe:
But even such a seemingly well-protected infrastructure still holds numerous risks and is open to a number of potential attacks:
Application injections to grab data from the database;
Backend vulnerabilities (remember the node modules?);
Weak protection of traffic – unreliable TLS certificates or weak settings;
Potential log overflows.
You also need to monitor the events all the time if you don’t want to miss potential threats. This leaves us with threat surface being basically everywhere! So what do we do now?
Defence in depth approach
Defense in depth is based upon one idea: regardless of the attack vector, a set of independent, yet interconnected, controls must be present for the whole data lifecycle. For most popular attack vectors, we want as many defence layers as possible. Military wisdom teaches us that narrowing the attack surface and determining typical data flow leads to the system’s stability.
To achieve both goals, we use cryptography. It narrows down the attack surface and data circulation flow in a predictable way. Authenticated encryption ensures that plaintext data is available only in few places covered by other controls.
We built all our tools around this idea – using strong cryptography as a core defense (general purpose open source encryption library Themis) and adding security controls to for double or triple protection of the bottlenecks.
You don’t have to build defense in depth from scratch, all these features are available in Acra.
Decryption proxy pattern for Defence in Depth
A perfect illustration of defense in depth approach to web application is a “decryption proxy” pattern: backend-side encryption and proxy-side decryption protect from data leaks from the sides of database and backend. SQL firewall and IDS help prevent unauthorized access to data.
Let’s see what the typical application flow is going to look like if we add defense in depth approach based on decryption proxy into this infrastructure:
The dataflow becomes very predictable and has two main directions: writing data to the database and reading it from the database.
In the scheme below, we use AcraServer as an exact implementation of decryption proxy, AcraWriter as backend-side application library that encrypt data chunks, AcraConnector as backend-side network daemon that provides authentication and transport encryption, and AcraCensor works as SQL firewall. However, you can build a similar scheme using tools you prefer.
This is what the process of writing of data looks like:
1. The backend app encrypts sensitive data into a special cryptographic container using public key of AcraServer. Let’s not go into the details of encryption, the main thing is that there is no way for the app to decrypt the data (because it doesn’t have a private key, so if backend app is hacked – it can’t decrypt the data).
2. The backend app sends encrypted data to the database through AcraServer. It is a server-side service that works as database proxy – it sits transparently between your application and the database and listens silently to all the traffic that's coming to and from the database. AcraServer monitors the incoming SQL requests and blocks the unwanted ones using SQL firewall (AcraCensor). AcraServer only sends allowed requests to the database.
3. As a result, database only stores encrypted data and knows nothing about the nature of the data (so if database is leaked, it can’t decrypt the data).
This is what reading the data will look like:
1. To retrieve the decrypted data, client application talks to the database via AcraServer.
2. Again, AcraServer monitors the incoming SQL requests and blocks the unwanted ones, saving the database from potential SQL injections (so if backend app is hacked to send SQL injection – it will be blocked by SQL firewall).
3. Upon receiving the database response, AcraServer tries to detect cryptographic containers, decrypts them, and returns the decrypted data to the application. AcraServer uses private decryption key (one per app, or even one per app user) stored in key storage (Vault, Amazon KMS, etc.).
All traffic between the app, AcraServer, and database is encrypted in motion (using TLS or general-purpose cryptographic transport protocols like Themis Secure Session, Libsodium, Noise Protocol) and all requests are authenticated.
As a result:
1. The attack surface on data is narrowed and has a predetermined expected behaviour.
2. The only entity that knows the plaintext is the AcraServer. The only way to get the plaintext from the database is to read it through the AcraServer. Both AcraServer, its keystore, database, and client app should be compromised for a successful plaintext data breach.
3. Separation of duties enables monitoring AcraServer efficiently – nothing but the regular flow should be taking place, any anomalies would be hard to miss. AcraServer should be under monitoring and logging control and be the source of events for SIEMs.
4. AcraServer provides anomalies related to its behaviour (local attacks) and any anomalous requests/responses.
5. AcraServer tracks audited log of client apps and queries that read/write sensitive data, so in case of an incident, there is a source of records for digital forensics and investigation.
If you are interested in seeing how Acra works in more detail, check out our GitHub. Moreover, Acra has a dozen other interesting security features (like built-in intrusion detection system based on poison records) and is available in Community, Pro, and Enterprise Editions.
This way, several various layers of defense stand between the attacker and successful data leaks on the path of every request:
Authentication: the attacker would need to get root access on the backend host.
SQL firewall: the attacker would need to bypass or go straight to the database (but in our scheme no sensitive plaintext can be retrieved from the database).
Stored data encryption: the database doesn’t know the nature of data, only AcraServer can decrypt it using the decryption keys (we insist on using unique sets of keys for every client application or user entity!).
Transport encryption: TLS / Themis Secure Session between the client application, AcraServer, database and back.
Intrusion detection system that detects suspicious SQL requests like
“SELECT *”(we didn’t cover it in details in this post, but we wrote a post fully dedicated to poison records previously).
Audit logs, monitoring, SIEM integration, honeypots and poison records – together with all the other data security means they constitute a system of interconnected controls that is rather hard to break.
We’re constantly adding more layers of defense to accommodate for various infrastructures to provide more layers of data-driven defenses.
Design your apps in such a way that in case of a data leak (or an inside job) the attackers are not able to get their hands on the real (plaintext) data. The defense in depths approach suits this task best: a set of independent, interconnected security controls over the data through the whole application flow. Cryptography works best as the foundation of Defense in Depth: it helps narrow the attack surface and build truly global defence layers.
If you have an already working complex web app, try using Acra to safeguard it. An encryption proxy at its core, Acra introduces a minor performance penalty, but it will provide you with all the described lines of defence and will considerably decrease the risks of a leak (and will also help you with GDPR compliance).
If you’re in the process of creation of your web app, take care to protect the data in advance. Try the demo and examples of our Acra where we’ve already configured it for certain architectures and all you need to do is to fill it with real business logic and data.