By David A. Wheeler
This post summarizes key steps that software developers can take to improve software security. It is a text version of a talk given at Open Source Summit North America (OSS NA) 2024.
Software is under attack. Attackers are looking for vulnerabilities to exploit, and today that does not mean only directly exploiting unintentional vulnerabilities in production software. Attackers are also trying to divert software developers to the wrong software via typosquatting & dependency confusion attacks. Attackers are trying to take over developer accounts, and sometimes they even play long cons to try to gain trust and insert malicious code into software as authorized maintainers (as exemplified by the recently-discovered attack on xz). Unfortunately, this includes open source software (OSS) Supply chain attacks on OSS are increasing. It’s not just OSS; as the attack on SolarWinds’ Orion software revealed, attackers are also attacking the supply chains of closed source software.
So if you develop software, you must develop and release it to resist attack. You must also take reasonable precautions when bringing in software from the outside (whether or not it’s OSS). The good news is that the Open Source Security Foundation (OpenSSF) has materials to help you do that! In this post I’ll particularly focus on key points from two OpenSSF guides, which then point to other materials:
- “Concise Guide for Developing More Secure Software”
- “Concise Guide for Evaluating Open Source Software”
First, when developing software, here are a few key points:
- Protect your accounts! Ensure all privileged developers (such as those who can commit or accept changes) use multi-factor authentication (MFA) tokens. At least use more than passwords, and don’t reuse passwords across sites. Attackers are trying to take over privileged accounts.
- Learn about secure software development. The OpenSSF has a free course on the fundamentals of developing secure software called “Developing Secure Software” (LFD121). OpenSSF has other courses too, e.g., Securing Your Software Supply Chain with Sigstore (LFS182x).
- Use a combination of tools in your CI/CD (Continuous Integration/Continuous Delivery) pipeline to detect vulnerabilities.
- Consider using Quality scanners (linters); Static Application Security Testing (SAST); Secret scanners; Software Component Analysis (SCA)/Dependency Analysis tools; Fuzzers; and web application scanners.
- Implement automated tests. In particular, include negative tests, that is, test that what shouldn’t be allowed to happen doesn’t happen. Many test suite developers, including followers of Test Driven Development (TDD), forget negative testing. Ensure the test suite is thorough enough to “ship if it passes the tests”.
- Don’t depend solely on tools. Tools miss vulnerabilities and are sometimes wrong when they report one. That’s why education is also necessary; you need education and tools. Most important, you need to THINK. Tools are not a replacement for thinking.
- Evaluate software before selecting it as a direct dependency. We’ll discuss that below.
- If it’s an OSS project, use the OpenSSF Best Practices Badge & Scorecard.
- Earn an OpenSSF Best Practices badge; this is essentially a project checklist form with some automation. At least earn “passing”, try for silver & gold. For more information, see: https://www.bestpractices.dev
- Improve your OpenSSF Scorecard score. This is entirely automated, which as with any tool, has strengths and weaknesses. Use the Allstar monitor. For more information, see: ​​https://securityscorecards.dev/
Here are a few pointers about developing software in various processes:
- Requirements: Make sure the software you produce is secure by default. If it’s insecure until the recipient configures it, then it’s insecure. There should be no default passwords. Communication over the internet should be encrypted by default.
- Design:
- Learn and follow design principles, such as least privilege & non-bypassability. Design APIs so they’re hard to use incorrectly.
- Prefer memory-safe languages where practical, otherwise use mechanisms like extra tools and compiler options to reduce risk. OpenSSF has a guide on C/C++ Compiler Options to help reduce risk in such cases.
- Do threat modeling aka attack modeling. This helps you view the software from an attacker’s viewpoint.
- Implementation:
- Learn the most common kinds of vulnerabilities for this kind of software & how to prevent them.
- Repository & build environment:
- Review changes before accepting them. Enforce such review, e.g., GitHub or GitLab protected branches.
- Improve your Supply chain Levels for Software Artifacts (SLSA) level. This hardens your build processes against attack.
- Release: Make it easy for users to get your software and verify that it’s the right software. Sigstore can help; it simplifies software signing and verification.
- Updates: Make it easy for your users to securely update by default.
- Vulnerability Reporting: Tell people how to report vulnerabilities.
Before adding a dependency, evaluate it. Here are questions we suggest you ask, per the “Concise Guide for Evaluating Open Source Software”:
- Can you avoid adding it?
- Are you evaluating the intended version? Counter “typosquatting”
- Is it maintained?
- Is there evidence that its developers work to make it secure?
- Is it easy to use securely?
- Are there instructions on how to report vulnerabilities?Â
- Does it have significant use?
- What is the software’s license?
- What happens on a test addition?
- What are the results of my own code evaluation? (if you can; a brief one can enlighten)
There is good news in all this. The price for unknown vulnerabilities (“0-days”) continues to rise, because attackers are increasingly finding it difficult to find and exploit vulnerabilities. That’s why attackers are increasingly trying to insert vulnerabilities into software before it is deployed. Thankfully, we can take steps to make it harder to insert vulnerabilities into software, directly or indirectly.
Security is a journey against intelligent adversaries. It’s not something you “do once and you’re done forever”. That said, by learning and continuously improving, the software you develop can strongly resist attacks.