A Guide to OWASP’s Secure Coding Practices Checklist
Home » A Guide to OWASP’s Secure Coding Practices Checklist
(7 votes, average: 5.00 out of 5)
In 2022, 33% of newly discovered vulnerabilities were flagged as critical or high. Explore OWASP’s secure coding practice checklist and learn how to leverage its power to boost your threat protection and reduce attack risks
Digitalization is both a blessing and a curse for organizations. From automation to fantastic new technologies and revenue streams, the opportunities offered by going digital are seemingly endless.
But, like everything else in the universe, where there’s a yin, there’s also a yang. The more digital technology you implement, the bigger your attack surface grows. And how do you mitigate the risk of a cybersecurity incident when in 2022, the top 10 vulnerabilities and exposures (CVEs) identified were found unpatched at least 12 million times?
The OWASP secure coding practices checklist is a useful set of prevention techniques. If integrated early into your software development process, these secure coding practices can tremendously boost the security of your applications, organization, and customers.
It’s a long list, though, so we won’t go through every checklist item. Instead, to save you time, we’ve picked what we think are the best secure coding practices in the checklist based on their:
Why do you need it? Before I start work every morning, I check the latest cybersecurity news and articles. I’ve been doing this for years, and guess what? I can’t recall a day without finding at least one vulnerability-related article making headlines. And those alerting about web application flaws are the most common ones.
Microsoft alone hit the jackpot in 2022, reaching a total of 1,292 vulnerabilities, according to data from Beyond Trust. That’s a new record high in a decade. Even the latest Verizon 2023 Data breaches investigation report (DBIR) shows basic web application attacks, representing one-quarter of all analyzed breaches, ranking among the top attack or breach patterns identified across all industries.
But why can’t you just agree on some best practices and follow them? No one says you can’t. But without a checklist or some other document, how would you know you didn’t forget to implement one of those best practices during development?
This is where the OWASP secure coding practices checklist comes in. Let me explain it with a real-life example. Have you ever had the chance to peek into the cockpit when boarding a flight? If you had, you may have noticed that the pilots go through one or more mandatory written checklists before taking off.
Why do they use them? Because no matter how experienced the pilots are, missing a step due to lack of concentration or too much self-confidence is easier than you think. Checklists help prevent aircraft accidents by ensuring no key step is left out.
The secure coding practices checklist does the same for software development security. It’ll help you ensure that every single agreed security requirement will be implemented at the right time. This way, you won’t have to go back and apply it just before release or deal with the consequences after the worst has happened.
A Closer Look at the Latest OWASP Secure Coding Practices Checklist
Now, the OWASP secure coding practices checklist is a 17-page document. It includes a collection of general methods that organizations can use to build secure software and protect their systems, applications, and customers from attacks and data breaches.
Do you really have to implement all of them? Ideally, yes, but you can also start by picking and choosing only the ones that best fit your situation. We’ve selected a few for you — let’s check them out one by one. Looking for an overview of the OWASP secure coding practices checklist? We’ve got you covered.
When available, prefer data structures that can’t be run (i.e., use non-executable stacks) to executable ones.
Check that the number of bytes to be written or read fits in the buffer. Otherwise, an attacker might exploit the data overflow to force the program to behave in a malicious or dangerous way.
14. General Coding Practices
Protect the integrity of code, executables and configuration codes with unique identifiers (e.g., checksums or hashes).
Prefer use of tested and approved managed code (i.e., running under the control of common language runtime – CLR) for common tasks instead of new, insecure, unmanaged code (i.e., executed directly by the operating system).
Review all secondary applications, third-party code, and libraries to determine business necessity and validate safe functionality.
Secure database updates by using encrypted connections.
Protect Your Software or Code With a Code Signing Certificate
Protect your software from tampering and build trust with your users by obtaining a code signing certificate. Sign your code with a digital signature that verifies your identity and assures users that your software is safe.
Websites and applications often require user input to complete specific actions. For example:
If you want to subscribe to a newsletter, you’ll have to enter your email address.
When you’re looking to buy something online, you’ll have to fill in your payment details.
If you try to access a web application or service, you won’t go anywhere without first entering your login credentials.
But if users can provide inputs, then so can cybercriminals. So, how do you guarantee that bad guys won’t exploit those fields to inject malicious code that enables them to steal sensitive data (i.e., passwords or credit card numbers), cookies, or session tokens?
The input validation (i.e., data validation) techniques listed below are excellent ways to check users’ and/or applications’ inputs for invalid or suspicious entries that could lead to code injection, obfuscation, and cross-site scripting (XSS) attacks.
Validate all data provided by the client before processing it. You can do this using an automatic process.
Validate all data based on parameters. Examples include data type, range, and length (e.g., determine a minimum and maximum length).
Classify and identify data sources clearly. You can do this by dividing them into trusted and untrusted (e.g., databases, uploaded files).
Validate data from untrusted sources. Everything that’s coming from databases, file streams, and external sources should go through this validation process.
Utilize canonicalization to address obfuscation attacks. In simple terms, transform untrusted data into a simpler, unambiguous form that can’t be misrepresented.
Let’s say an attacker manages to inject malicious code into your online customer’s registration form. If executed, the sensitive data entered by the customer will be redirected to the cybercriminal. How do you prevent it?
There are several methods to protect your application and users from this type of XSS attack. These listed below are some of the most effective:
Sanitize all output of untrusted data to operating system commands. For example, eliminate dangerous tags and attributes, or replace them with safe values.
Ensure the output encoding is safe for all target systems. This way all encoded outputs will never be interpreted as code but only as text.
Contextually sanitize all output of untrusted data to queries for SQL, XML, and LDAP. Understand the context of the data and select the right encoding method based on that. Use existing libraries, if available; it’ll prevent mistakes and it’ll be faster and easier to implement.
Contextually encode all output data sent from external sources to the client. Once again, sources like file streams or external sources are included in the untrusted category.
Conduct all output encoding on a trusted system. Basically, use a trusted system to translate your output data into a non-dangerous format to help prevent XSS attacks. This should be done server-side only, not client side, using a well-protected server.
Did you know stolen credentials were the most common attack method in 2022? They accounted for 90% of breaches analyzed by the previously mentioned Verizon 2023 DBIR report. Between 2016 and 2022, ReliaQuest reports a stunning 24 billion usernames and passwords were compromised!
Protect the main door to your web applications by implementing the following:
If your application manages a credential store, use cryptographically strong one-way salted hashes. Storing only salted (and peppered) password hashes deriving from strong algorithms (e.g., SHA-256) instead of saving them as plain text. This way even if a hacker gets hold of the password hashes, he won’t be able to use them.
Enforce password complexity and length requirements established by policy or regulation. Require the use of unique, long and complex (i.e., alphanumeric characters, capital letters, and symbols) passwords. Check the National Institute of Standards and Technology’s (NIST) password guidelines for useful password recommendations.
Avoid using failure responses that indicate which part of the authentication data was incorrect. ‘Invalid username’ or ‘The user doesn’t exist’ are not secure responses because it tells an attacker which specific info was wrong so they can try again. Opt for the vague ‘Invalid username and/or password’ message instead to make their job harder.
Use HTTP POST requests (instead of GET) to transmit authentication credentials. Why is the POST approach more secure than GET? Because with POST, the credential information is stored in the request’s body instead of being displayed in the URL as URL query parameters (which makes GET requests visible to everyone).
Only send non-temporary passwords over an encrypted connection or as encrypted data. Passwords are sensitive data, and like all sensitive data should always be encrypted, no matter if they’re in transit or at rest (i.e., stored in a database).
Have you ever noticed that when you log in to your bank’s website, your login session is terminated after a specific timeframe? On mine, there’s even a funky countdown. Why? It’s a common way to protect you from breaches and session hijacking. And it’s also part of the industry’s most secure coding practices — OWASP included.
What about you? How do you handle users’ requests to a service or web application? Check out these highly scalable solutions:
Don’t allow concurrent log in attempts with the same user ID. Enforce one log in (session) for each user ID. That’s it.
Establish a session inactivity timeout that is as short as possible. In other words, try to limit how long a session remains idle before it’s automatically terminated by the server in a way that’ll balance risks and business functional requirements. I know it can be annoying for users to be kicked out of a system, but it’ll protect organizations from attackers trying to exploit idle, authenticated sessions.
Logout functionality should fully terminate the associated session or connection. When a user clicks on the ‘logout’ button, they must be logged out completely. If this isn’t the case, it’s time to make changes.
Generate a new session identifier if the connection security changes from HTTP to HTTPS. Why? Because HTTP is insecure and prone to man-in-the-middle (MITM) attacks. Think about the authentication process. If the identifier remains the same when the connection switches from HTTP to HTTPS, a cybercriminal could intercept and use it to access password-protected areas.
Do you remember the Cambridge Analytica scandal that fined Facebook $5 million? Let me refresh your memory. In 2018, the consulting company Cambridge Analytica gained access to millions of users’ personal information. They did this by exploiting a broken access control vulnerability in Facebook’s application programming interface (API) that allowed any third-party developer access to sensitive user data.
Don’t risk letting everyone on this planet access to your most valuable assets — add the following to your secure coding practices checklist:
Grant the least privilege possible to service accounts and those connecting to and from external systems. How? Apply the principle of least privilege so that users get access only to what they need to do their work.
Implement account auditing and enforce the disabling of unused accounts. To avoid issues, do it regularly and often, not only when a colleague leaves the company. People change roles all the time, and so should their permissions.
Enforce authorization controls on every request, including those made by server-side scripts. Do you need to allow long sessions? Don’t forget to periodically re-validate the authorization.
Restrict access to files or other resources to only authorized users. The same goes for access to protected URLs, functions, and files or resources outside the application’s direct control.
Limit the number of transactions a single user or device can perform in a given time. Keep the limit low enough to deter automated attacks but above the actual business requirements. For example, automatically lock an account after a user has entered an incorrect username or password three times in a row (in a specified number of seconds).
In 2018, the hotel chain Marriott was a victim of a data breach that exposed more than 5 million unencrypted passport numbers. As a result, the company had to cover the costs of new passports for the affected customers requesting them and fork out at least $3.5 million in data breach expenses and legal fees.
Cryptographic keys (i.e., private and public keys) used in conjunction with algorithms and public key infrastructure (PKI) digital certificates will protect your sensitive data at rest (e.g., stored in databases) and in transit (i.e., sent from one device to another) against tampering and snooping. Using cryptographic processes and tools is like wrapping your data with a protective layer that makes it unreadable and virtually impossible to modify (so long as you follow secure key management and certificate best practices). Therefore:
Another interesting finding of the earlier mentioned Verizon DBIR is that 74% of breaches involve human elements (e.g., mistakes, misuse). And some of the mistakes developers make involve how their applications handle errors. We get it; finding the right solution can be tough sometimes. Here are a few secure coding practices from the checklist that can help:
Use error handlers that don’t display debugging or stack trace information. Doing otherwise will be like giving the combination of your safe to a thief.
Implement generic error messages and use custom error pages. Always remember, anything your users can see can be also seen by the bad guys. Make your error messages and pages as impenetrable as possible, and never incorporate sensitive information in error responses. (Pro tip:MITRE’s Common Weakness Enumeration (CWE)-209 shows a few examples and a list of improvements to protect your web applications by not giving away too much valuable information that attackers can use.)
Log all authentication attempts, especially failures. Be sure to log everything related to connection attempts with invalid or expired tokens, input validation failures, access control, potential tampering events, or security configuration changes.
Use a cryptographic hash function to validate the integrity of your log entries. While this isn’t necessarily a common approach, you could hash your logs to offer assurance that a log entry hasn’t been modified by an attacker.
Protecting data from being lost, compromised, altered, or stolen is essential for any organization. To do so without breaking the bank:
Use cryptography to store highly sensitive information, including server-side authentication verification data. Protect your credentials, email addresses, customers’ credit card numbers, and more using strong cryptographic algorithms.
Protect server-side source code from being downloaded by a user. Why should a user need to download such codes? Always remember: if something is not needed, it should be either deleted, deactivated, or restricted.
Disable auto-complete features on forms expected to contain sensitive information. Yes, auto-completing forms (including authentication forms) are cool and can save your users some time. However, not everything cool is also safe. Do without it. Better spending two more minutes filling in a form than hours fixing a data breach.
Don’t store passwords, connection strings, or other sensitive information in clear text or insecurely. Yup, no matter what type of sensitive information you store, cryptographic functions are your best bet to protect it against cybercriminals (especially client side). Make sure you pick the correct algorithm and your data will be out of harm’s way.
Bonus: These simple but effective actions will also facilitate compliance with other privacy and data protection regulations required by the industry like the:
Encryption is a powerful ally in securing email communications and data transfers. If you’re still transmitting information via the unprotected hypertext transfer protocol (HTTP), you’re putting your customers and data at risk of MITM attacks.
Don’t follow in the footsteps of UC Browser, a popular Android web browser. In 2019, more than 500 million users were exposed to MITM attacks when downloading a package kit from an insecure channel. To avoid this, use a transport layer security (TLS) certificate to safeguard your data in transfer and ensure that:
Prevent failed TLS connections from downgrading to insecure connections. Want to protect your connections and data in transit from poisoning (i.e., attackers injecting false information into a system) and MITM attacks? Stay away from insecure and deprecated old protocols (e.g., SSL or TLS 1.1).
Use active, valid TLS certificates that include intermediate certificates in their trust chains. Why? Have you ever seen the browser warning ‘Your connection is not private’ or ‘The connection is not secure’? Yup, that’s caused by an expired certificate. It happened to Pokemon Go back in 2018 and it was all over the news. You also want to ensure that the certificate has been issued by a trusted certificate authority (CA) to the correct domain name.
Specify character encodingsfor all connections. In other words, convert characters into a format good enough for transmission and storage.
Utilize TLS connections for all content requiring authenticated access and for sensitive information. This will help you add another layer of security to your data and shield them from prying eyes.
Want to know how secure your TLS protocol is? Test its configuration and more with Qualys SSL Server Test. It’s free, and you just need to enter your hostname.
10. System Configuration
Let’s go back for a moment to Verizon’s 2023 DBIR. One of the highlights shows that 19% of data breaches were caused by insider threats’ errors (i.e., unintentional security gaffs) and malicious misuses (i.e., intentional actions).
Incorrectly configuring your systems and/or applications can cost you dearly. To avoid the most dangerous mistakes, include in your checklist the following actions:
Implement an asset management system and register system components and software in it. Include a software bill of materials (SBOM), which is a complete list of system components (including third-party ones) and software in an application. It’ll help you keep track of vulnerabilities and updates.
Isolate your development environment from production and restrict access to it. Keeping your development environments isolated and granting access only to those who need it (e.g., developers and testers) are effective ways to keep your production code safe from prying eyes.
Turn off the directory listing. The list of the files and folders hosted on your web server should remain private. You don’t want to give attackers a detailed map of your server, right?
Ensure servers, frameworks, and system components have all patches issued for the version in use. How can you do that without investing too much time? Do you remember when we talked about the SBOM? Time to put it to use now, and you’ll be done in a blink of an eye.
11. Database Security
Over 2.8 million — this is the number of the U.S. retailer SimpleTires’ customer records that were exposed and available for at least three weeks to anyone with an internet connection. How did it happen? The data was stored in an insecure database. It didn’t even require a password!
Shocking, huh? Now, ask yourself: How secure are your databases? Here’s how to provide them with an acceptable level of security that’ll preserve them from most attacks:
Use unique, secure credentials for database access. Strong passwords and the use of Multifactor authentication (MFA) should become the norm.
Remove or change all default database administrative passwords. Do you know how easy it is to find a default password for the most common applications? Just run a search on the internet. You’ll be amazed at how many entries you’ll find.
The application should use the lowest possible level of privilege when accessing the database. Why? It’s an effective way to minimize damage. In case an attacker manages to break into the application, the most important data in the database will be safe.
Turn off all unnecessary database functionality. Let’s declutter! Get rid of unused and vulnerable functions. The fewer functionalities you have, the less work you’ll have to do, and the more you’ll reduce the chances of an attacker breaking in.
Keep your customers and applications safe from malware attacks:
Validate that uploaded files are the expected type by checking file headers rather than extensions. Remember that file extensions are much easier to rename than changing a file’s header.
Scan user-uploaded files for viruses and malware. The open-source malware scanner ClamAV is just one of the software programs available to do the job.
Use an ‘allow list’ of permitted file names and types when referencing existing files. The file name or extension doesn’t match your whitelist? That might be dangerous then.
Is file security a major issue within your organization? OWASP has a cheat sheet with a plethora of suggestions to help you fix it once and for all.
13. Memory Management
Buffer overflow is one of the top 25 SANS CWE’s most dangerous software errors. Why? Because attacks based on buffer overflow (i.e., occurring when a program attempt to write more data into a memory that it can hold) enable cybercriminals to run malicious codes, crash programs, or corrupt data.
The following tips will help you to properly manage memory and avert memory-based attacks:
Utilize input and output controls for untrusted data. This will block any malicious input entered by an attacker.
Use non-executables stacks, if available. It’ll shield your memory against malicious shell code injection and help prevent buffer overflow exploitation.
Check buffer boundaries if calling the function in a loop and protect against overflow. Translate in simpler words, and check that the number of bytes to be written or read fits in the buffer to avoid overflow. Is it really so important? Well, it’s one of the root causes of the Heartbleed bug.
Pro tip: Memory vulnerabilities are dangerous. Nevertheless, they can be minimized also by using programming languages less likely to make applications susceptible to memory attacks as suggested in the U.S. National Security Agency’s (NSA) Software Memory Safety guide.
14. General Coding Practices
Yeah, you made it! You managed to get to the last point of the OWASP secure coding practices checklist. Well done! Before we wrap up, let’s have a look at a couple useful general coding tips included in the secure coding practices checklist:
Review all secondary applications, third-party code, and libraries to determine the business necessity and validate safe functionality. It’ll help you avoid introducing new vulnerabilities. When possible, use only signed third-party codes so that you can always check the validity of their signatures.
Implement safe updating using encrypted channels. Encrypt the connection using a TLS certificate to keep attackers at bay.
Use checksums or hashes to verify the integrity of interpreted code, libraries, executables, and configuration files. You don’t know how to verify a checksum? Learn how to do it in Windows and Linux.
Use tested and approved managed code rather than creating new unmanaged code for common tasks. The managed code should be properly signed to allow you integrity, authenticity, and originality validation. It’ll guard your application against malware infection.
Final Thoughts on A Beginner’s Guide to the OWASP Secure Coding Practices Checklist
My grandma used to say, ”A stitch in time, saves nine.” The secure coding best practices you’ve just learned, if applied early in the SSDLC (long before your web application is released), will help you prevent the most common cyber attacks. A few quick takeaways include:
Always validate your data,
Protect your communications and codes with digital certificates, and
Secure your databases with multifactor authentication.
There are enough solutions for every situation and need. Select the ones you’re most comfortable with and start mitigating the risk of the most common vulnerabilities. Did you find this article useful? Top it up by reading our next article. A deep dive into the absolute essentials that your code review checklist should cover. Don’t miss it!
Code Signing Best Practices
Want to keep your software and code safe?
Enter your contact information below below to receive your FREE Best Practices PDF:
Contact details collected by CodeSigningStore.com may be used to send you requested information, blog update notices, and for marketing purposes. Learn more…