Software development is a practice that more and more people around the world are engaged in. There are both companies and individuals building software, some of it proprietary, some free or open-source, and some is an amalgamation of the two. Since threats to the security of users or their software do not materialize out of the ether as soon as something is declared complete and shipped to production, it seems like the right time to talk about security practices that would help manage security risks that might creep into your software during the development process. There are several SSDLC (Secure Software Development Life Cycle) frameworks, including ones from OWASP, CISA, and NIST (SSDF). In this article, we’ll borrow a bit from all of them to highlight a few practices aimed at helping you manage the risk inherent in software development. Do not live with a sense of false security thinking it cannot happen to you. Check Point 2023 mid-year cyber security report reveals an 8% spike in global cyberattacks over 2022, and the trend doesn’t seem to be reversing.
What is The Software Development Life Cycle
Software developers aim to build software fast, accurately, and securely. Of course, you can’t always get all three. Over time, the development process was divided into several distinct phases that can fit any software development. These phases can be broken down as:
- Requirement analysis – what are we going to build and why
- Planning – how we’re going to build it in general terms
- Software design – how we’re going to build it in specific terms such as architectural design
- Software development – writing and compiling the software
- Testing – make sure it works as planned
- Deployment – ship it or publish it so the end user can use it
There are a few other versions of this cycle but overall they are very similar. It’s important to remember that the cycle isn’t a one-off thing – It doesn’t usually end once you shipped to the client or published it to the cloud. There are almost always problems you need to deal with that might require re-design (back to square one), bugs you need to fix, features you want to add, and so on. You can also find yourself working on a few stages in parallel or stopping mid-step to double back. Since none of the steps is inherently security-centric that leaves security to constantly play catch-up with the development process and in today’s hectic development speeds it’s not enough.
The Importance of Securing Your SDLC
Secure software development aims to include security considerations in all stages of the process, not treating security as an add-on to the proccess. In this way security should always be a consideration no matter what phase of the process you’re engaged in – thinking about the project requirements, planning out the architecture, considering the building blocks and infrastructure required, and sitting down to develop the code. This approach is sometimes called the shift-left security approach.
Here, shift-left refers to distributing security concerns throughout the development process and involving the developers in security design, implementation, and testing.
It can be intimidating for developers who have never really thought about security issues to suddenly have to deal with it. It is significantly easier to handle if the requirements are divided into multiple well-defined best practices. You can think of it like picking up a new IDE.
The more well-defined the requirements and the more automation and comprehensive tools you can employ, the easier the tasks will become.
SDLC Security Best Practices
Here are a few best practices to help you secure your development process in no particular order:
Training – Many developers would feel unequal to the task of applying security considerations and testing to the code they’re writing. The majority of developers are aware that letting tainted input data into your backend can result in remote code activation, much like the well-known “drop tables.” Fewer people would, however, be familiar with buffer overflow testing or vulnerability scanning for tertiary (or further) dependencies. Developers can close these knowledge gaps with the use of training. Developers are better equipped to incorporate security concerns into their daily coding and testing when they have a deeper understanding of security challenges and potential vulnerabilities. It also makes much more sense for the developer who wrote the code and is intimately familiar with its function to consider its security gaps and plan the testing accordingly.
Scanning – You can use many types of scanning to make your code more secure overall. Static, dynamic, and interactive analysis are a few of them. Static analysis looks for evident coding flaws or possible security vulnerabilities in source code. It can be used to look for potential vulnerabilities, insecure code practices, and violations of coding standards. It doesn’t consider run-time events because it examines the code syntax only. Dynamic analysis looks for any security flaws, coding faults, and other issues in the application while it’s running. It can be used to identify memory leaks, subpar operations, and possibly unstable inputs or processes. Keep in mind that since this type of testing is conducted at a certain time using specific inputs, the quality of the tests depends entirely on the individuals who devised them. The aim is to find the issues before your users do. Interactive analysis examines the application to find any potential security flaws and other breaking issues. It can look for possible vulnerabilities, usability problems, and problems with the user interface. The more comprehensive scanning tools you utilize the better protected you are but the trade-off is, of course, in development speed. Since each application is unique it’s up to you to find the balance between the right amount of scanning and the desired speed of development. Additionally, we recommend creating a complete SBOM of your application and applying various scans and reports to that source of data as well. Having an SBOM legacy of your app is a good way of keeping very detailed component and package information that could be invaluable for numerous security reasons.
Code reviews – Examining source code to find any security flaws, coding mistakes, and other software flaws before it’s combined with the active development branch is known as code review. Typically, a developer with greater expertise than the one who authored the code conducts this review. Such reviews can aid in guaranteeing that the code is well-written and the application is safe. Additionally, they support the upkeep of a single standard and coding conventions (such as function and variable names) throughout the whole code base.
Allowing the integration of code into the main branch after at least two pairs of eyes have reviewed it is regarded as a best practice. The developer who authored the code is, of course, the first pair of eyes. It can be beneficial for even highly skilled engineers, such as team leaders, to have someone else evaluate their code. At the very least this ensures more than one person is familiar with each section of the code. Bear in mind that at times of great stress or at a time crunch people might consider foregoing this element. If possible, consider adding this rule as a hard-coded element of your CI/CD so that it cannot be bypassed.
Testing – We don’t have to tell you how important it is to test your code to discover security flaws before they become an issue. The majority of code projects are intricate and interconnected, therefore it is impossible to foresee how a single, little gap can eventually impact the security of the entire code base.
When writing automated tests, take into account the functionality of the recently produced code as well as any significant back-end and front-end interactions with other parts of the code base.
Vulnerabilities like SQL injection, cross-site scripting, unsafe data storage, and inadequate memory allocation (which could result in buffer overflows) are examples of security issues that are typically addressed in testing. Testing ought to address memory leaks, sluggish or unreliable performance, and usability. The testing should be automatic and integrated into the CI/CD pipeline so that no new version or update can be published without undergoing both unit and integration tests.
Independent pen testing – No one can think of everything and as developers, we sometimes develop blind spots in regards to the code we wrote. Similar to code review, independent pen testing allows for a fresh approach and another set of eyes to critically examine what we did and the precautions we took to secure our app and our users. Such tests are recommended at least once a year and should incorporate infrastructure evaluation as well as app vulnerabilities.
Use open-source securely – Almost all software in development today includes open-source software to a greater or lesser degree. Open-source components are some of the leading causes of imported vulnerabilities into your application, either directly or through transient dependencies. Additionally, it’s not only the libraries you use that can endanger you – but it’s also failing to update old libraries or to keep up to date with the latest published CVEs that might impact you. We recommend creating a list of approved open-source packages for use by the organization and constantly checking and updating it. Preventing the developers from adding any package they want to, even if just as a test, could help cut back on the number of vulnerabilities you have to deal with.
Make sure vulnerabilities do not turn into exploits – There is almost no code base devoid of vulnerabilities. Any decent scan would turn up anywhere from hundreds to thousands of them. It’s impossible to eliminate them all. It’s also important to remember that vulnerabilities are not exploits. Make sure you have a filtering process to make sure any vulnerability you discover is not an exploitable threat and keep this list constantly updated. In this way, you can calm any third parties or users concerned about the latest CVE that it has absolutely no impact on your application.
Security Starts With Your Mindset
There are probably as many different ways to develop software as there are developers, frameworks, and coding languages. That is to say, it’s not easy to find best practices for securing your development process that would be relevant no matter what language, field, or IDE you’re employing. Beyond a plethora of tools, some proprietary and some free, all clamoring for your attention as ‘the next irreplaceable security tool’, the most important security tool you can employ is your mindset.
Think about your design choices, architecture, and storage. Have you considered the option of exponential growth in your user base? Have you properly segmented access privileges for different parts of your codebase and infrastructure? Did you consider both a targeted attack against your data or secrets and a software supply chain ’indirect’ attack?
All these questions and more should be considered before you even sit down to plan your application and they should be routinely reinspected as the codebase and app grow and evolve.
It’s considered an axiom that the most vulnerable part of any software is the human running it (or writing it). Don’t let your application, software, or code library be part of the increasing statistics of a new wave of cyber attacks. With proper planning, tools, and automation you can find the right balance between managing cyber risk, securing your development life cycle, and producing well-documented, comprehensive, efficient code.