Some notable things we have achieved so far:
- all of our projects score A (or higher) on securityheaders.com
- we started using Matomo instead of Google Analytics
- security advisor is a formalised role within the company
- we work using a secure development lifecycle (or SDL), but more on that in another blog
An important part of our SDL1 is continuous security training. By this, we mean that everyone at the company takes at least one security-relevant course every year, thereby ensuring awareness across the team. One way we facilitate this is by organising annual security sessions that highlight a specific topic. This year, I picked the topic of Threat Modelling, which took shape as a workshop provided by Eleanor Saitta. Eleanor is a renowned software security architect and consultant who, luckily for us, operates her consulting company Systems Structure Ltd. remotely.
The workshop filled two mornings, the first in the form of a lecture and the second of Eleanor coaching us through the process of creating a model for one of our projects. In this blog I want to highlight what we've learned and what distinguishes Trike (a method co-created by Eleanor) from other threat modelling methodologies.
As TG's security lead, I could talk for hours on why security is important for organisations and how a breach, by not considering security early on, could cost them a fortune, if not their entire business. But let's assume we're already convinced, stick to the topic and have a look at when to do threat modelling.
Most people may recognise the following graph (even though I drew this particular one myself). It illustrates that the further you are in a project, the higher the costs of fixing a security bug are.
Most organisations implement security measures like penetration testing or some form of security code review, which have their place on the timeline during, for example, the "Test" phase. Organisations may even implement a form of threat modelling. A lot of these methods identify threats based on an architectural model of the system. These models are generally developed after the initial phase of the project, for example in the "Design" phase, when a lot of crucial decisions on requirements have already been made. This situation is illustrated as follows:
Now, this is where Trike really shines. As threat models are based on a requirements model, one can start with it as soon as, and I quote Eleanor, "you start thinking about the application". This will help to identify security requirements early on, making them significantly cheaper to add.
A quite unique part of the requirements model of Trike I'd like to highlight is the fact that it focusses on the assets you are trying to protect and not on the types of attacks that have to be mitigated. The rationale behind this is quite simple: the list of attacks out there could be infinitely long (the CWE list has 1419 entries at the time of writing) and an attacker would only need one to compromise the system, whereas we would like to ensure that we find all possible weaknesses of a system. Therefore, it makes very little sense to focus on a myriad of (unlikely) possibilities, if you can also zero in on the (un)intended actions of your project.
A final thing I would like to point out, is that a threat model makes a great piece of documentation in general, as it contains a well structured set of functional requirements. By starting early, it can be used as a reference when difficult-to-implement functionality is worked on, and new team members can use it to quickly get a good understanding of what the system is supposed to do.
I hear you thinking: how does this all work? Well, stepping through the method is not really part of this blog, but in short, creating a requirements model consists of the following two steps:
1. Define your Assets, Actors & Intended Actions
These are basically what your system is intended to do. Using the well known TODO example app, we might end up with a table of intended actions like this:
To provide some context; in this example some TODO's are readable by anyone, but only users can create new ones.
2. Extract failure cases
Using the intended actions, for each asset one assesses the risks of an "Escalation of Privilege" (EoP) and a "Denial of Service" (DoS), which we call the "Failure Cases". If you're familiar with STRIDE, you could see this as a simplification of the threats to just the "unintended actions" and "denial of intended actions".
In order to make sure that all possible failure cases are handled by the system, the final step is to list the so-called security objectives. This is a structured way of writing down how the system will react and what measures are taken to prevent the failure cases from happening. If we focus on the "high" cases, one could end up with:
- When anonymous attempts to read an account, the system will respond as if the account doesn't exist.
- When a user attempts to delete another user's TODO, the system will prevent it from doing so.
- When anyone attempts to DoS the read of TODO's, the system will detect and log the attack, and rate-limit the attacker.
Adding the failure cases completes the requirements model and provides the team with a comprehensive list of security requirements. These will make it much easier, and quicker, to securely implement all functionality. Note that if business requirements change, the requirements model also needs to be updated, but as you won't have to start from scratch this will generally work really well in an agile development process.
Now that the requirements model is done, the Trike methodology continues with modelling threats on the architectural model using a so-called Data-flow Diagram. This can be used to annotate "trust boundaries", which are very useful to determine wether rules are enforced in the correct places. But as this is very similar to most other methodologies, I won´t go into that in this blog. It is important to note, that a complete requirements model is enough to start working on the design of the system and that it is not necessary to also complete the architectural model first. The architectural model can be made during the Design phase and in any diagram style you are used to, as long as the trust boundaries can be drawn. The architectural model completes the threat model.
If you´d like to see an example of a full threat model, stay tuned for future blog posts by Arjen!
Take home messages
All in all, this blog highlights just a part of what Trike is, but I hope the message is clear: start on a threat model for your project as soon as possible (i.e. now). Or, to summarise in a few more words:
- A threat model defines "what security means for a system". Modelling this early on makes it much easier to implement a system securely and prevents common mistakes and misunderstandings.
- By focussing on assets and intended actions, Trike makes sure that a complete list of failure cases is covered by enumerating them in a structured manner.
- Describing how a system should respond in every case, a threat model makes great documentation for developers and on-boarding new team members. As requirements are prone to change it is a living document that should evolve with the system.
- Starting on a threat model early on will save a lot of time, and therefore money, later on, as requirements are a lot cheaper to add in the beginning of a project.
I am convinced that a threat model is invaluable to any system that calls itself secure and I really hope that in the future more software will be shipped with one included in their documentation. To lead by example: at Tweede golf we started making them for our most critical projects, but more on that some other time.