Security teams traditionally have come in towards the end of the software development lifecycle. In many organizations this has led to the perception that security is a blocker to software delivery teams. The industry has made enormous strides over the last few years as the “shift left” movement has taken the industry by storm. But security teams are frequently still disconnected from the software development lifecycle. As security teams continue to integrate with their software development partners, they’ve found the need to not only threat model their applications, but how the applications are delivered as well. This article is meant to help security teams begin their threat models and make more informed risk management decisions regarding their software development practices.
Designing for failure has been a core principle ingrained into technology industry insiders. We apply this to how we configure our cloud resources, how we build our kubernetes deployments, and even how we set up our server hardware cabling and power systems.
Mature software development practices as we know them today, are a curation of lifetimes of failure modes and effects analysis for software development into a common body of knowledge. This body of knowledge reflects the best practices of software development as we know them today. So to understand mature software development practices, we must first understand how software development can fail.
The three pillars of operationally ready software are:
The threats to each of these pillars form the foundation of what we know as mature software development practices today.
Sustainable software is software that is able to support or maintain a process or set of needs over time.
Approximately 70% of a standard application code today is open source code and created by someone outside of your organization. The remainder is code your team authored, or hacked together from stackoverflow. Even with 70% of code being code that you did not author and are dependent on, unmaintained software is a rampant issue. In their 2022 Open Source Security and Risk Analysis Report, Synopsis reported that 88% of projects contained components that had no new development in the past two years. The OWASP foundation has even made unmaintained third party components part of the 2021 OWASP Top 10.
Use of unmaintained software components makes fixing bugs, security vulnerabilities and quality your responsibility. Many organizations accept that responsibility but some prefer to outsource that to a community supporting the component. Just ask the thousands of organizations that still depend on the unmaintained protocol buffer solution gogo/protobuf.
Mature software organizations manage the sustainability of their software by either accepting the cost of maintenance of the component themselves or refactoring their code to remove unmaintained third party components.
Trustworthy software is software that gives you assurances. You trust that the authors are doing due diligence to ensure that software is secure, reliable and free of bugs. In general, most people have a higher level of trust for software run by a known community, such as corporate sponsored open source over software designed and managed by a single anonymous maintainer.
The emerging standard for software component trust is Supply Chain Levels for Software Artifacts (SLSA). SLSA defines three key categories of threats to trust: Source Integrity Threats, Build Integrity Threats and Availability Threats.
Source Integrity Threats are threats that could introduce unauthorized or ill intended changes to source code and involve the submission of unauthorized changes, and the compromise of source repositories.
To reduce the risk of unauthorized changes organizations require multi-factor authentication and often require the signing of commits to reduce the likelihood that an authorized user is compromised. Mature organizations also take steps to ensure that each change to source code requires informed review from skilled personnel. Mature software development shops frequently do this by using branch protection rules on protected branches, or important locations in the source code submission process generally associated with the promotion of code from testing to staging or production environments.
Several prudent branch protection rules are generally used to ensure an informed review by a trusted user is required on all branches:
- Require a pull request before merging - Forces users to go through a formal review process to merge changes to code.
- Required number of approvals before merging - Forces users to obtain a set number of approvals before being able to merge changes to code.
- Dismiss stale pull request approvals when new commits are pushed - Ensures that modifications to code after an approval must be re-reviewed
- Include Administrators - By default branch protection rules do not apply to Administrators, unless this branch protection rule is configured.
- Require signed commits - Forces commits to be signed to be merged to the protected branch.
Mature development shops generally have configured policies to enforce these rules across source code to reduce source integrity threats.
Build integrity threats are threats that introduce modifications to source code or the build process to modify the integrity of a build and component deployment process.
Organizations frequently have commitments to testing processes as contractual obligations to their customers. These processes usually include running application security testing tooling, linters and application test suites against code to ensure code quality. These commitments generally result in manual auditing processes driven by third party independent audits or audits directly from an organization's customers. Those leading the industry are seeking to change this paradigm by using automated processes to attest that the solutions provided to their customers meet their contractual commitments to quality.
To reduce the risk of process deviations from a build process, these leading organizations are beginning to adopt or have already adopted the in-toto standard. The standard defines a layout of who can perform what action and from where for each build. This ensures that an auditable process is run against. These organizations run completely automated builds with a technically enforced and auditable process against those builds.
Availability threats are threats that may cause a software component or the code to build that software component to no longer be available.
To reduce the risk that an external dependency may no longer be available many organizations use local caches of packages from external package repositories or vendor their dependencies.
Quality software is software that is useful, generally free of significant bugs, and secure. Software quality failures typically include functional bugs, security vulnerabilities and performance issues, which could impact organizations differently depending on the functional use of the software.
The primary proxy used by developers for software quality is popularity of a source code repository. Developers frequently rely on the wisdom of crowds to determine if a software package that meets their use case requirements is quality. Outside of the wisdom of crowds, several quality assurance practices are used by mature organizations to ensure that software is developed securely and bug free.
- Automated testing runs on each committed change - Automated and fully scripted builds with a set quality standard and gate are commonly used to set a quality bar for software development.
- Static security testing and software linting - Mature organizations look for common source code patterns that introduce bugs both security related and functional are reviewed throughout the software development lifecycle.
- Software composition analysis - Ensures that organizations have visibility into the vulnerabilities within their dependencies and quality gates for the severity of those vulnerabilities.
- Dependency management tools - Help to automate updates to software dependencies to ensure they are reasonably up to date and alert users to security vulnerabilities.
By building software with continuous review for software sustainability, trust and quality, mature organizations reduce their risk of failure in various forms. This is the foundation of mature software development practice.