The original article appeared on the OpenSSF blog. The author, Harimohan Rajamohanan, is a Solution Architect and Full Stack Developer with Wipro Limited. Learn more about the Linux Foundation’s Developing Secure Software (LFD121) course.
All software is under continuous attack today, so software architects and developers should focus on practical steps to improve information security. There are plenty of materials available online that talk about various aspects of secure development practices, but they are scattered across various articles and books. Recently, I had come across a course developed by the Open Source Security Foundation (OpenSSF), which is a part of the Linux Foundation, that is geared towards software developers, DevOps professionals, web application developers and others interested in learning the best practices of secure software development. My learning experience taking the DEVELOPING SECURE SOFTWARE (LFD121) course was positive, and I immediately started applying these learnings in my work as a software architect and developer.
“A useful trick for creating secure systems is to think like an attacker before you write the code or make a change to the code” – DEVELOPING SECURE SOFTWARE (LFD121)
My earlier understanding about software security was primarily focused on the authentication and the authorization of users. In this context the secure coding practices I was following were limited to:
No unauthorized read
No unauthorized modification
Ability to prove someone did something
Auditing and logging
It may not be broad enough to assume a software is secure if a strong authentication and authorization mechanism is present. Almost all application development today depends on open source software and it is important that developers verify the security of the open source chain of contributors and its dependencies. Recent vulnerability disclosures and supply chain attacks were an eye opener for me about the existing potential of vulnerabilities in open source software. The natural focus of majority of developers is to get the business logic working and deliver the code without any functional bugs.
The course gave me a comprehensive outlook on the secure development practices one should follow to defend from the kind of attacks that happen in modern day software.
What does risk management really mean?
Key takeaways on risk assessment:
Analyze security basics including risk management, the “CIA” triad, and requirements
Apply secure design principles such as least privilege, complete mediation, and input validation
Supply chain evaluation tips on how to reuse software with security in mind, including selecting, downloading, installing, and updating such software
Document the high-level security requirements in one place
Secure design principles while designing a software solution
Design principles are guides based on experience and practice. The software will generally be secure if you apply the secure design principles. This course covers a broad spectrum of design principles in terms of the components you trust and the components you do not trust. The key principles I learned from the course that guide me in my present-day software design areas are:
The user and program should operate using the least privilege. This limits the damage from error or attack.
Every data access or manipulation attempt should be verified and authorized using a mechanism that cannot be bypassed.
Access to systems should be based on more than one condition. How do you prove the identity of the authenticated user is who they claimed to be? Software should support two-factor authentication.
The user interface should be designed for ease of use to make sure users routinely and automatically use the protection mechanisms correctly.
Importance of understanding what kind of attackers you expect to counter.
A few examples on how I applied the secure design principles in my solution designs:
The solutions I build often use a database. I have used the SQL GRANT command to limit the privilege the program gets. In particular, the DELETE privilege is not given to any program. And I have implemented a soft delete mechanism in the program that sets the column “active = false” in the table for delete use cases.
The recent software designs I have been doing are based on microservice architecture where there is a clear separation between the GUI and backend services. Each part of the overall solution is authenticated separately. This may minimize the attack surface.
Client-side input validation is limited to counter accidental mistakes. But the actual input validation happens at the server side. The API end points validates all the inputs thoroughly before processing it. For instance, a PUT API not just validates the resource modification inputs, but also makes sure that the resource is present in the database before proceeding with the update.
Updates are allowed only if the user consuming the API is authorized to do it.
Databases are not directly accessible for use by a client application.
All the secrets like cryptographic keys and passwords are maintained outside the program in a secure vault. This is mainly to avoid secrets in source code going into version control systems.
I have started to look for OpenSSF Best Practices Badge while selecting open source software and libraries in my programs. I also look for the security posture of open source software by checking the OpenSSF scorecards score.
Another practice I follow while using open source software is to check whether the software is maintained. Are there recent releases or announcements from the community?
Secure coding practices
In my opinion, this course covers almost all aspects of secure coding practices that a developer should focus on. The key focus areas include:
How to validate numbers
Key issues with text, including Unicode and locales
Usage of regular expression to validate text input
Importance of minimizing the attack surfaces
Secure defaults and secure startup.
For example, apply API input validation on IDs to make sure that records belonging to those IDs exists in the database. This reduces the attack surface. Also make sure first that the object in the object modify request exists in the database.
Process data securely
Importance of treating untrusted data as dangerous
Avoid default and hardcoded credentials
Understand the memory safety problems such as out-of-bounds reads or writes, double-free, and use-after-free
Avoid undefined behavior
Call out to other programs
Securely call other programs
How to counter injection attacks such as SQL injection and OS command injection
Securely handle file names and file paths
Securely send output
How to counter Cross-Site scripting (XSS) attacks
Use HTTP hardening headers including Content Security Policy (CSP)
Prevent common output related vulnerability in web applications
How to securely format strings and templates.
“Security is a process – a journey – and not a simple endpoint” – DEVELOPING SECURE SOFTWARE (LFD121)
This course gives a practical guidance approach for you to develop secure software while considering security requirement, secure design principles, counter common implementation mistakes, tools to detect problems before you ship the code, promptly handle vulnerability reports. I strongly recommend this course and the certification to all developers out there.
About the author
Harimohan Rajamohanan is a Solution Architect and Full Stack Developer, Open Source Program Office, Lab45, Wipro Limited. He is an open source software enthusiast and worked in areas such as application modernization, digital transformation, and cloud native computing. Major focus areas are software supply chain security and observability.