67% of developers knowingly release applications with vulnerabilities. Learn 10 secure coding practices that every developer should know and make secure coding part of your organization’s DNA
Did you know that researchers recorded 50% more cyber attacks per week globally in 2021 compared to 2020? And with SonicWall identifying 318.6 million more ransomware attacks in 2021 than the previous year, it’s no surprise that organizations are trying to include security into processes as soon as possible.
But “shifting left” takes time. Much like how Rome wasn’t built in a day, application security integration doesn’t happen that quickly, either. However, there are things that you can do straight away to implement secure coding.
In this article, you’ll discover how 10 secure coding practices that you can implement right now can put you on the right track. You’ll learn how to make your applications more secure and vulnerabilities-free right from the very beginning.
Secure Coding: It’s Better to Be Safe Than Sorry
Being a developer is a bit like being a magician: with coding, you can make tests appear or disappear, create floating buttons, and other wonderful features. Magicians and developers also have something else in common: security. One has to ensure that the code developed is secure, and the other has to guarantee that how he performs his tricks remains secret.
There are different ways to do that, but if you’re a developer, you usually have two choices:
- Fix your vulnerabilities at the end of the development lifecycle. Write your code and, just before releasing the application, check and fix any vulnerabilities you find at the end.
- Make security part of the development process right from the beginning. This entails checking for vulnerabilities along every step of the development progress and fixing them as you go along. This way, you don’t have to rush just prior to releasing your secure application.
Which one would you choose? If your answer is the second one, congratulations! You’ve made the right choice. Now, let’s have a look at how you can do that.
10 Secure Coding Practices You Can Implement Right Now
Secure coding is a group of best practices that’ll enable you to secure your code as you go. In this article, we’ve selected for you the most important ones. And, as brevity is the soul of wit, we’ve also summarized them in one handy table.
|Coding Practice||How to Implement It|
|1. Input validation: Never Trust User Input|
|2. Manage Authentication and Passwords|
|3. Sanitize Data First, Then Send the Inputs to Other Systems|
|4. Adopt the Principle of Least Privilege|
|5. Architecture: Make It Unique and Secure|
|6. Keep It Intuitive But Effective|
|7. Deny Access by Default|
|8. Go Deep With Your Defense: Create Multiple Security Layers|
|9. Secure Your Work and Communication|
|10. Check the Quality of Your Code and Follow Coding Standards|
1. Input Validation: Never Trust User Input
Securing user input is a big deal for any application. It’s basically the first line of defense. Get this under control and you’ll easily avoid most vulnerabilities. And it doesn’t matter where the input comes from: trusted or untrusted sources, everything has to be validated. Why? Because everyone makes mistakes and not everyone has good intentions.
Including input validation in your code will enable you to check that the input entered by the user (or attacker) is how it should be. If not, the data will be rejected, typically while displaying a 400 HTTP error message. Checks generally are based on:
- Data length (e.g., telephone numbers).
- Characters set (e.g., email addresses).
- Format (e.g., dates).
- Restrictions (e.g., no code or scripts allowed).
Have you ever seen an error message like “Please enter a valid email address” when you entered your email address on a web form and forgot to type the “@” special character? This is the result of implementing input validation. Because being trusting is good when it comes to friends and family, but it’s better to not trust when it comes to security.
Looking for some input validation coding examples? Check out the following resources:
- GitHub’s blog article on input validation
- OWASP’s input validation cheat sheet
- RedHat’s input validation video
2. Manage Authentication and Password
Managing authentication and passwords can be tricky, but there are ways to ensure that your data and applications are accessed only by those who are authorized and properly authenticated to do so. Implementing proper authentication and password management processes will make your application less vulnerable to attacks like brute-force and credential stuffing. As such, the following tactics also can help you to mitigate the risks of data breaches:
- Use transport layer security (TLS) client authentication. This process involves the server sending its TLS certificate to the client during the TLS handshake process to validate the server’s authentic digital identity.
- Implement proper (i.e., generic) authentication error messages. If your error message clearly states that a specific username doesn’t exist, the user will know it, but it means the attacker will, too. And this will give him an advantage. Never give out too much information. This will ensure that if the authentication fails, the user (or bad guy) will get a generic error message that doesn’t provide them with info they can use to try to access the application.
- Store, control and manage your passwords safely. Asking your employees to create strong passwords only takes you so far. You also need secure password storage. Storing password hashes instead of plain text passwords in your database and implementing a good password recovery mechanism for users will help keep your sensitive information away from prying eyes.
- Transmit password data securely. If the login landing page or other authenticated pages aren’t using a strong encryption mechanism like TLS to secure the connection, the attacker will be able to view the unencrypted session ID and get access to sensitive data.
- Never store credentials within the app’s script. Even if embedding credentials as plain text into codes can be handy during development, it’s never a good idea. Why? Because often people forget to remove the credentials before publishing their code on sites like GitHub. This serves up your credentials as a feast to bad guys, and that can have serious consequences for you and your customers. For a real-world example of this type of situation, just look at what happened to Uber back in 2016…
Do you want to know more about authentication and password management? Check the links below to get useful tips and examples:
- OWASP’s Authentication cheat sheet.
- Google’s suggestions for good authentication and password management.
3. Sanitize Data First, Then Send the Inputs to Other Systems
While input validation will check the format and size of the data entered, data sanitation will remove any unsafe characters. It’s like a two-step quality control process at a fruit stand: first, the quality and size of the fruits are checked, then all those rotten (unsafe) to ensure that they don’t spread mold to the other products.
Likewise, data sanitation will ensure that if a breach happens, it’ll be contained and the attackers won’t be able to exploit unused functionality for SQL or other injection attacks. How can you do that?
- Use a whitelist (allowlist). Including the desired characters or strings in a whitelist will ensure that only those you selected will be retained. Think about telephone numbers. People write them down in different ways: separated by hyphens, dots, or brackets. With a whitelist, you can ensure that only the numbers will be retained, for example.
- Use a blacklist (blocklist). It’s the opposite of the whitelist. Basically, your list will include all inputs that might pose a threat to your system, enabling you to remove unwanted HTML tags or non-conforming inputs. This can help you detect and stop some of the more obvious input-based attacks, even if keeping the list updated can be a challenge.
- Escape to keep your code and system safe. Probably the best solution among the three, you won’t have to bother with long lists of wanted or unwanted input here. Based on the assumption that every input is unsafe (do you remember? Never trust user input), it takes the data and secures it prior to putting it in a query. How? Essentially, by adding a special character (e.g., \\ or \\n and more) before a string or character to ensure that it’s interpreted as you want (e.g., as text and not as the end of a string). This process is known as escaping.
4. Adopt the Principle of Least Privilege (PoLP)
Access to secure facilities is strictly regulated in highly secure facilities like banks, government offices, or military installations. Access is limited to the minimum to reduce risks and to help avoid breaches. The same approach should be applied to applications: a customer service agent shouldn’t have access to the company’s payroll data, and your chief financial officer doesn’t need access to your network’s active directory or SSH portal.
Every process should be executed using the minimum privileges necessary to complete. Additional permissions should be only granted for the time taken to complete a specific task reducing the chance of an attacker exploiting those permissions. How can you achieve this?
- Validate permissions on every request. .NET Core and Java filters are a good way to perform permission checks correctly.
- Create tests to validate permissions before release. This will help you ensure that all permissions set up in the design phase have been applied correctly.
- Periodically review permissions. After the app has been deployed, plan and execute regular permission reviews. People change job roles and, when they do, they might not need the same permissions.
Learn more about the principle of least privilege
5. Architecture: Make It Unique and Secure
Do you want a secure application? Think and act like an Egyptian pyramid architect from ancient times. To keep their tombs safe from treasure hunters, they were always coming up with new ways to make their architecture unique and challenging for unwanted intruders to figure out.
Therefore, to make an invulnerable application, don’t copy an old architecture; design your own and add your own security policies. We get it; doing this can be difficult, but a good architecture doesn’t have to be overly complicated as long as it’s well thought through. With the Egyptians, it worked so well that some treasures and tombs still remain uncovered today.
But how do you go about creating a unique infrastructure?
- Use subsystems. If you need several levels of privileges, ensure you divide your system into subsystems, each with a distinct privilege set and able to communicate with the others.
- Follow OWASP’ secure architecture (SA) practice. Stuck on your design? OWASP’s SA resource can guide you through the architectural design of your application.
- Load only secure plugins and libraries. Use only secure directories to avoid an attacker tricking your users into downloading malicious code that may be then loaded and executed by your application.
6. Keep Your Architecture Intuitive But Effective
Wow! You’ve really impressed your audience by showing a demo of your latest, full of cool features application. Even your boss was fascinated. However, while all those bells and whistles may have looked nice during your presentation, you may have forgotten to consider that an application with a simple design is much easier to manage and secure.
Because the more complex the design is, the more likely it is that errors will be made during implementation, configuration, or usage. The same goes for securing the application: the more complex it is, the more time you’ll have to invest in implementing security mechanisms.
- Use a no-frills and small design. This has been proved efficient in reducing the number of flaws by J. H. Saltzer and M. D. Schroeder’s study, “Protection of Information in Computer Systems”
- Don’t over-complicate your security controls. Overly complex security controls that are difficult to maintain can harm the system administration of your infrastructure, lowering the security of your system.
- Be user-friendly. Once again, an overcomplicated design will be reflected on the users that will be tempted to circumvent the security control. Not good.
7. Deny Access By Default
Configuring your application to make the access decision based on permission rather than exclusions is much more efficient and secure. Why? Because maintaining a list of exclusions is much more time-consuming and prone to errors than giving permission to a user when needed.
This may leave you wondering what this process entails. Configuring your app so it’s permission-based helps you:
- Keep unauthenticated users out. No unauthenticated users should be able to access your application’s admin page.
- Apply this policy to new user accounts too. Do you have a new colleague? Ensure that when they get their new ID and password, they can’t access any sensitive systems by default until their account is properly configured.
- Keep new features sealed. Have you just released a new feature? Make sure no one can access it until it’s properly configured.
To learn more about it, check OWASP’s proactive control list.
8. Go Deep With Your Defense: Create Multiple Security Layers
Did you know that the U.S. Transportation Security Administration (TSA) has implemented 20 layers of security to secure its aviation transportation system? Why? Damage control: If one layer fails, the vulnerability may be contained or even stopped by the next one. It’s like when a bad guy manages to go through the check-in process using a counterfeit passport and then he’s stopped at the gate by law enforcement officers who were alerted by Customs. The same can be applied to application development.
There are a few ways you can create layers within your organization’s IT systems:
- Configure the security settings of each application. One size doesn’t fit all. An application that connects to the internet needs more sophisticated protections compared to one that doesn’t connect to the internet.
- Pair secure programming with secure runtime environments. This winning combination will help you reduce the risk of undetected vulnerabilities that could be exploited once the code is released.
- Don’t forget authentication checkers. Once the application is released, if an attacker manages to find a way to get through an unpatched vulnerability, the authentication checks you’ve implemented may save your day (and your business).
9. Secure Your Work and Communication
Protecting your work is paramount when you’ve invested so much time and effort in coding and developing a new app. To do so, you don’t need to reinvent the wheel. Take advantage of built-in security features and known techniques such as:
- Using strong, readily available cryptography. Ensure you encrypt your data both while it’s in transit and in storage (i.e., secure your data at rest). Always be sure to use strong and valid encryption and hashing algorithms to secure your data and protect its integrity.
- Hardening your database. Your database is precious and even a small incident (e.g., code injection or table dropping) can have serious consequences. If reading access is enough, never give write access; also be sure to parameterize your queries and close connections as soon as possible.
- Using trusted security certificates. Always use digital security certificates (think SSL/TLS certificates for web apps) released by a well-known certificate authority (CA). Ensure that they’re properly configured and keep an eye on their expiration dates.
- Signing your code before releasing it. Use a code signing certificate to digitally sign your app before releasing it to prevent tampering. Your digital signature confirms to customers that what they’re downloading is safe and authentic.
10. Check the Quality of Your Code and Follow Coding Standards
Attackers are just waiting for you to make a mistake so that they can jump on the opportunity and use it to their advantage. But errare humanun est! In other words, making mistakes is human nature and vulnerabilities evolve all the time. However, there are ways to find errors and fix them before they can be exploited.
- Review your code regularly. Schedule regular code reviews to check for security issues. You can also combine it with automated tools that scan your code (many are free) for vulnerabilities.
- Use effective quality assurance mechanisms. Fuzzing and penetration testing, independent security reviews, and code audits are a few examples of good techniques that’ll help you identify flaws in your code.
- Use coding standards developed by international bodies. Coding standards — for example, SEI CERT coding for JAVA, C++, and Android OS or MISRA C for C programming language — will make your application more secure and help you ensure that no vulnerability is left undiscovered. This will reduce costs and development time. You can also prepare a list of coding guidelines specific to your organization.
- Prevent attacks with threat modeling. Regularly examine your application design to identify weaknesses that could be used to compromise your code. Categorize the threats you found and proactively mitigate the risk of attacks.
- Implement an effective patch management process. Releasing patches and updates at regularly scheduled intervals will ensure that your organization won’t fall behind the patches released. Most importantly, it’ll give you enough time to test them thoroughly before implementation. However, that’s not enough. An emergency procedure (use it sparingly!) should also be part for your patch management process. This will avoid delays in case of urgent patches.
Last but not least, if you want to know more about security as code or you’re still feeling a bit insecure and want to go the extra mile, check out our latest article “What Is Security as Code & How Can I Implement It” and OWASP’s Secure coding practices checklist
Final Thoughts On 10 Secure Coding Practices You Can Implement Now
The threats organizations face today, if not prevented, can have dire consequences for you and your users. For this reason, delivering secure software has become crucial for every organization. Achieving a well-designed, efficient, and generally secure code is not impossible. All you have to do is start to get rid of bad habits and include in the application development life cycle the secure coding practices discussed in this article.
Of course, we understand that it’s impossible to make your software 100% secure. However, you can do everything within your power to make it as secure as possible and to make it harder for cybercriminals to compromise.
Ward off security flaws and start delivering secure software today by integrating secure coding best practices into your SDLC and procedures. Protect your applications from attacks, safeguard your customers’ data and increase your customers’ trust. Become a secure code warrior now!