According to a recent report – security looks to be a top concern among Software Architects. In this article I go into detail on one of the core ways in which you can achieve dependable security in evolving online systems – namely defense by depth.
What is defense by depth?
Simply put this is where one control would be reasonable, we put more controls that approach risks in different fashions. Such controls, when used in depth, can make severe vulnerabilities extraordinarily difficult to exploit and thus unlikely to occur. In essence you have created a design ‘lock’ in which all the different tumblers (or Controls) have to be triggered at the same time to gain access.
Another way to view it is as a series of gates or doors that have to be all unlocked at once to get access, the Intro to Get Smart below is a good visual representation (except for that the doors actually need locks..).
Defense by depth is one of my favorite techniques as it can be both implemented within a system module or as part of a larger architectural design. Also you can use it as a method to literally mess with hackers minds if you are really good at it (i.e. they cannot work out what worked or didn’t, their ability to ‘dig’ into a system becomes a lot like trying to dig into quicksand).
Both of these approaches have their own advantages and disadvantages as follows:
Defense by depth within a system module
Often this is done in online systems in the display controllers or associated routing logic middle ware – the goal here is to combine several different features of the request which all have to match in order for it to be processed correctly, for instance:
- Request comes from a certain sub-net,
- Request has a valid session cookie;
- Cookie refers to a valid user account;
- Said user account has the role to access the page.
You have to get all 4 of these right to do anything with the page in question. Now if you are really paranoid – you could also add in:
- Request has to be over HTTPS
- Request has the correct Nonce for the action.
This will protect against a Man-in-the-middle attack and a Nonce to stop Cross Site Request Forgery (CSRF).
The ‘fun’ with this is you can add other Controls or attributes to check which also have to match for the specific case in hand (what if the User Agent changes or the IP shifts?). Although do note there is a fine line between being more practically secure and being more annoying to your real users.
Defense by depth within an Architecture Design
This is rather like what you would do within a system module, but you set up the architecture design so the Controls (and what they check) is distributed sensibly across distinct systems (by distinct I mean they are separate in a security sense, running them on the same machine environment defeats the benefit). For instance the system which checks your users passwords is structurally distinct to the system which stores application data. In other words you have a distinct Authentication Service. Now this has several architectural advantages as follows:
- The systematic footprint that is aware of how passwords are stored and checked is small, this makes it easier to ensure its secure and stops key password information ‘leaking out’ up your stack.
- Given the Authentication Service is distinct behind a strong API, you can evolve this independently of its clients.
- If the Authentication Service is used by many clients you can unify your response to hacker attacks with ease as well as ensure the right level of logging is being performed.
- Maybe you can even replace it with an OTS (Off The Shelf) solution – but this has its own problems (data ownership, access controls, SLA’s, security models, etc).
This also encourages what I call functional encapsulation – or only those who need to know how the password system works need to know. It also encourages your clients to think about it as a black box which just does what it says in the tin.
You can also apply the Defense by depth technique to other sensitive types of information (like PII) and ensure that is also held within its own system behind its own API.
Now I know a lot of programmers will be groaning about how we have split everything up, but in this day and age the overheads of calling another system for often one off data checks (you don’t need to check the password with every request or you are decidedly doing something wrong!) vanishes into the processing swamp compared to everything else you are doing. Which is better, putting all your eggs (password hashes, emails, addresses, telephone numbers, etc) in one basket, so a successful hack against you losses you all the eggs – OR do you do some basic separation of concerns via API’s and present a much less attractive and incomplete data set for the taking – which is also easier to secure?
Note: I’m not against putting data together in systems, but data needs be considered as to whether it should be together by the following qualities:
- How often it is referenced – Would you put often referenced data together with data hardly ever used?
- It’s security value to the business – Password hashes, account balances, credits, etc are a lot more critical than say someone’s mailing preferences.
- The value of the data to its owner – You don’t ‘own’ peoples names, addresses, telephone numbers, etc they are attributes of a person or a legal entity, so have value of their own distinct to what you think is their value – this is the so called PII data.
- The ‘varsity’ of the data – or in other words your trust in it being true and the effort taken in keeping it true.
So to me, where data lives is just as important as which data it is kept with – proper consideration of this leads to more naturally secure systems that scale easier and are more ‘adaptable’ in their design, the data just happens to be in the right place at the right time.
Bonus: Whats the #1 cause of security breaches in online systems?
Simply put it is often changes with unintended consequences – somebody makes a change, be it in code or configuration and suddenly a hole appears in the security of the system that the hackers jump right through…
Now defense by depth, but within modules and at the architecture level is your best defense against this – hands down. All the automation and quality control is never perfect and an accidental opening of a port (or the dropping of a whole firewall), or an enabling of a debug feature will be a lot less painful if defense by depth is employed in your architectural designs. Such events become a minor issue instead of a major pain.
If you would like help with how to apply Defense by Depth in your Software Architecture designs – please do get in touch .