The role of secure coding in DevSecOps
Secure coding as an integral part of DevSecOps - How does it relate to effectively addressing security challenges?
Back in 2019, we examined DevSecOps concepts through the lens of software security. But with the ever-growing popularity of DevSecOps comes increased pressure on developers to deal with security issues. Indeed, even back in 2022, GitLab’s Global DevSecOps Survey showed that 53% of developers were fully responsible for security in their organizations and they felt much less confident about these responsibilities compared to “Dev” and “Ops” tasks.
So it is time to revisit the topic in 2024 – how does knowledge of secure coding come into the picture? We think secure coding is integral – invaluable, even – to help developers establish and maintain a good security posture in line with for DevSecOps.
Is (Dev|Sec|Ops){2,3} just another buzzword?
DevOps emerged in the late 2000s in an effort to combat the conflicts and inefficiencies caused by the worlds of developers and system administrators being completely separate, especially when using agile development methodologies. DevOps’ weapon of choice is the cross-functional team (via cross-pollination, even): developers have to learn a bit about infrastructure management and sysadmins have to hone their coding skills to help with flexibility and responsiveness. This process uses heavy automation.
In the early 2010s, software security issues have become truly mainstream. While vulnerabilities and breaches have always existed, dealing with them required specialists – usually external penetration testers showing up to ruin everyone’s day during the last phase of development. This purely reactive approach was insufficient in the face of potentially company-destroying risks, thus it was necessary to employ the multidisciplinary approach again, and expand developers’ horizons with security expertise – hence, DevSecOps. Just like DevOps, it’s not just a hyped buzzword – it’s addressing a very real problem.
Just as with DevOps, this is realized through a heavy reliance on automation – after all, there’s a limit to how many hats someone can wear, and a developer couldn’t be expected to act as a full-fledged security expert in addition to everything else they’re responsible for. So how is DevSecOps related to secure coding skills (which are clearly in the wheelhouse of a developer)?
Earlier has always been better
“Shift security left” is a core principle of DevSecOps. One of the main drawbacks of the “old ways” was how security was something to ‘do’ after development has concluded, as an afterthought, which could lead to massive headaches. Some significant findings could even force re-engineering of the entire system, which is extremely expensive.
Secure coding plays a crucial role here – in fact, building security into each step of the SDLC (instead of just doing a single penetration test at the end) has been a vital part of software security all along, emphasized by Gary McGraw’s Building Security In: Software Security paper from 2004. If a developer knows how to implement something correctly the first time, there won’t be any deep-seated design or implementation flaws for the tests to find and fix – and then it’s a win-win!
All the gear, no idea?
Automation is central to DevSecOps, especially via automated security checks within the CI/CD pipeline. Static and dynamic security testing tools (SAST and DAST) are all important here, but they’re not (and cannot) be perfect at uncovering all possible security weaknesses in the system. Whoever uses these tools needs to understand what kind of vulnerabilities they can (and can’t) deal with.
Furthermore, even if a tool uncovers a vulnerability, actually fixing the issue is not always as simple as adding the SameSite attribute to a cookie or rewriting an SQL query to use prepared statements. One should understand all details holistically to be able to address the findings correctly. For example, fixing something like an SSRF (server-side request forgery) vulnerability needs the developer to understand the concepts of the attack surface, input validation, allowlists, and the potential impact of such a vulnerability against the deployment environment (Why isn’t the firewall stopping this attack? What happens if the attacker targets the metadata service?).
The role of secure coding is clear here: knowing about the vulnerabilities (and the appropriate best practices to prevent or mitigate them) can make these new-old responsibilities much easier to bear.
A few extra links in that supply chain
The security of the software supply chain has always been critical, but nowadays with a greater reliance on third-party (frequently open source) components it’s become a bigger target than ever. Many of the high-profile hacks from recent years (such as Solarwinds in 2020) targeted the build environment to compromise the project as it was being built. In DevOps, continuous integration and deployment (CI/CD) is crucial, and this automation also increases the attack surface as well. Aside from Solarwinds, there were examples of backdoors being hidden in code repositories, broken IAM, dependency confusion attacks, and compromises of third-party services.
Managing dependencies (and their potential vulnerabilities) is an important part of secure coding, too. Beyond trusting the vendor, verifying the authenticity and integrity of packages and modules and checking for vulnerable components via software composition analysis (SCA) tools such as OWASP Dependency-Check are still as important as ever. Of course, if a piece of software has a large number of dependencies, manual oversight may not be too feasible. This is where the software bill of materials (SBOM) comes in: a comprehensive machine-readable list containing all supply chain relationships of various components and dependencies used in building software. OWASP’s CycloneDX is a critical tool in this area.
Burglarizing the house that Terraform built
Infrastructure as Code (IaC) is an important part of DevOps, as it automates the creation and deployment of infrastructure components (usually VMs and containers). And just like ‘regular’ code, the configuration files and scripts can be vulnerable too! For example, if the attacker can trick someone into installing a malicious Terraform provider, it can cause RCE analogous to a regular command injection during execution. Failing to secure golden images and containers properly (security patches, secure configuration, hardening) makes them an easy target for attackers.
So what does secure coding have to do with any of this? In particular, IaC access control and permission management is analogous to implementing similar systems in code, and the same rules apply – e.g. using the principle of least privilege to only give the minimum privileges necessary to the accounts that execute Terraform code. And of course, vulnerability management and secure configuration best practices apply to VMs and containers just as well.
Exposed secrets
It’s often necessary for a component to access a secret (password, API key, or other credential) so it can authenticate itself to another component – and the easiest way to solve this problem is to just store the secret directly in the source code! While convenient, this exposes the password to anyone who can read the source code or reverse-engineer the binary. What’s worse, if the code is later committed to any kind of code repository, the password is practically exposed forever and is as good as compromised. And, unfortunately, this keeps happening.
This is a long-recognized problem in secure coding (see CWE-259 and the more broad CWE-798), and of course we all know that secrets should never be hard-coded in the source code. Instead, they should be stored in key vaults, hardware security modules (HSM) or – at least – keystore files following best practices such as OWASP’s Secrets Management Cheat Sheet. DevSecOps helps a lot here with a variety of automated tools that scour code repositories for possible credentials (e.g. git-secrets).
“We are not so different, you and I”
At its core, DevSecOps is about making sure that security controls are correctly integrated and enforced without slowing down development. Modern software security initiatives like OWASP have been expanding into the DevSecOps world as well. Of particular interest are OWASP DevSecOps Maturity Model (DSOMM) (listing various DevSecOps security activities to integrate into the SDLC) and the OWASP DevSecOps Verification Standard (DSOVS, still under development) which defines a set of DevSecOps security requirements in checklist form. There are initiatives focusing on specific DevSecOps aspects as well – such as the list of the Top 10 CI/CD Security Risks.
And teaching employees in various teams (not just developers!) about secure software development best practices is a critical part of that. We consider DevSecOps to be an integral part of any modern software development lifecycle, and have security courses specialized for the needs of Dev(Sec)Ops engineers in particular. For instance, in Secure coding and security testing in C# for DevSecOps, we cover typical vulnerabilities of C# web applications combined with secure build and CI/CD pipelines in the Azure cloud context using Docker containers and Kubernetes orchestration – all with a focus on properly using and understanding automated security testing tools.