Building good software is hard. Building good software that’s also secure is even harder. Arguably, the very definition of “good software” is also software that’s secure, but security is just one of many qualities expected of software development teams and, more specifically, on engineers. This list is getting longer all the time: validate your input; remember the correct encoding context; don’t take dynamic input into your SQL (structured query language) queries; use security headers; update your libraries — to name just a few. It’s a nontrivial amount of cognitive overhead, which is where secure defaults can help.
How Secure Defaults Work
Secure defaults can make the packed life of a development team easier. Set up the system to work by default in a way that supports the outcome that you’re aiming for. This dynamic has been applied in many different capacities, including school lunch programs and 401k savings, building on principles from behavioral economics. Clint Gibler gave a fantastic talk on applying this principle and supporting it via build-time tests.
The pursuit of secure defaults can open conversations about technology stack selection. Programming languages, development frameworks, middleware, and various other tools have different advantages and disadvantages. There is no perfect tech stack. Every application has unique needs, a unique problem to solve, and a unique threat model. Yet teams must be intentional about the curation of their technology stack so that it works for them, handling key security needs by default. This is where layers come into the picture.
Secure Defaults Layers
There are numerous opportunities to create secure default dynamics. Building on my comment above about threat models, let’s first consider what classes of vulnerabilities are most important. For example, injection attacks may be quite prevalent, or maybe there are issues around authentication or cross-site request forgery; these insights could come from vulnerability data review, threat model analysis, or insights from adversarial exercises like penetration tests.
Secure defaults can be introduced at multiple points, depending on the capabilities of the technologies in use. Places worthy of investigation might include:
- The programming languages directly (for example, Python being largely safe against memory corruption vulnerabilities like buffer overflows)
- Within the development frameworks used
- As part of features in extension libraries to the development frameworks
- As configuration options associated with the infrastructure resources used in the operating environment (e.g., cloud services that can automatically handle encryption)
- Within peripheral technologies used as part of the operating environment (e.g., WAFs (web application firewalls), middleware, key management, etc.)
The concept of secure defaults doesn’t have to be taken literally, and it doesn’t have to be a lot of work. With some engineering and creativity, it’s likely possible to create security controls that are applied automatically or as close to it as possible with little added effort. The goal is ultimately to reduce the development team’s cognitive overhead so they have one less thing to worry about in the journey to build secure products.
There are several ways to pursue a secure-by-default strategy, and there are also many different classes of vulnerabilities to tackle. Keeping the focus on the cognitive load that doing security work entails will keep developer experience in the foreground. If doing the secure thing is the easier thing, it’s much more likely that the outcome will be favorable for security teams down the line as well.
Want more cybersecurity insights? Subscribe to the Cybersecurity as a Business Enabler channel: