Defence in Depth Meets the Software Development Life-cycle
Security in software development can get time consuming. Thinking about it in an Agile way can save time and may even be better...
Security should be an integral part of the software development lifecycle (SDLC) from start to finish. I often find “lifecycle” is synonymous with the waterfall methodology, but what I mean here is any software development at all, whether it’s created using waterfall, agile, or something else.
Security in the SDLC doesn’t need to be some vast time-consuming pit of effort either, it can be sprinkled across the lifecycle to give major improvements to security without too much effort, creating a layered, “defence in depth” style approach.
How do we achieve useful levels of security with minimal effort?
- Knowledge is an excellent starting point
- Security gates - at key points across the work you should really focus on security
- There are lots of free tools that can save you time (see builds / testing below)
Below are some examples of security gates which might happen during software development for a product, or even just a feature of a product.
Consider what data we need to use, is it Credit Card number, Personally Identifiable Information (PII), or just publicly available information? The data involved should drive thoughts about how much we might need to think about security as we go.
What are the moving parts, what data is moving around and where is it moving, what does our potential attack surface look like?
At this stage it’s worth deciding if we need to do a threat model to dive deeper into the security requirements, so we’ll look at the functions and the data to see how important they are. A threat model is likely to be one of the more time-consuming areas of security, potentially taking a few people hours or even days, so it’s important to focus on key areas where problems could occur. Some of the key areas may have already been highlighted when thinking about the analysis.
Larger bodies of work may be split into tasks. We need to consider separate tasks and what the likely impact is on security for each. We may decide that some tasks require little to no security work and that’s ok, as long as we actually put the thought in and drew that conclusion.
If we decided there is a security impact then before we start coding we’re trying to think about what we’re going to change, how we’re going to do that and what impact on security those changes might have. This information can be used to feed into coding the solution and try to improve security from there. This could easily come in as a 10 minute task, just spending a small amount of time really focusing on security.
We’ll also be taking any security tasks that were required by the threat model, anything we thought was important for security should get done. There will be different priorities for these security tasks and some may not need to be done before the feature goes live.
Unit and integration tests are written as the code is written, where it should hopefully be trivial to ensure things like user access controls and input validation are successful. Those tests will be run regularly alongside code as it changes and will ensure secure code doesn’t later become insecure code.
At the end of coding we need to look at the complete code with a secure code review and see if it still matches with what we see as secure code. Small features shouldn’t take too long to have a secure code review done, perhaps a maximum of an hour.
Once code is checked in to the repository we look to automated tools to catch problems we may have missed. Tools like static code analysis and dependency checkers are relatively simple to automate as part of the build process and easily catch things that us mere mortals miss. Once they’re automated there is little to no maintenance, although setting automation up to start with may be a little time consuming, it’s clearly be worth it once done.
Unit and integration tests should also be run here to ensure everything (not just security features) runs as expected.
After builds, the working software may be deployed to one or more environments, likely going to development or QA environments first. Ideally a deployment will be scripted so that it runs in the same way every time and important steps don’t get missed – some of those important steps may be security related.
Once software is deployed to an environment, further security testing can be done. This can take the form of tools like OWASP ZAP, which can perform dynamic security testing. ZAP can also be automated, which again is useful to keep repetitive / manual effort to a minimum.
Once software passes everything above, it can be a candidate to go into a live environment. At this stage thought may be given to penetration testing, before a new product goes live and at regular intervals.
The above are all “security gates”, points at which security needs to be checked before code can move towards deployment. We need to really focus on security at these gates and that’s why I refer to it as “putting my security hat on”. These are points where I’m not trying to think like an architect, analyst or developer, instead I’m focusing purely on security, I’m thinking like an attacker.
Not all of these security gates will be needed all of the time, where I currently work we make decisions as a team as to how much security is likely to be impacted by a feature we’re about to work on. If there is likely little to no impact then we may forgo things like threat modelling or even secure code reviews.
Using these typically lightweight gates across the development of features means we’re thinking about security regularly. We have multiple points in the process where we can pick up security problems, almost like defence in depth for the software development process.
Got a comment or correction (I’m not perfect) for this post? Please leave a comment below.
Subscribe to Gavin Johnson-Lynn
Get the latest posts delivered right to your inbox