No products in the cart.
It’s super important to consider the security of the applications you build. There are lots of ways to address security issues, but a powerful way to get started is to address the top ten security issues as identified by OWASP (the Open Web Application Security Project). In this article, we’ll walk through the current top ten security vulnerabilities for applications.
OWASP is an international organization dedicated to the security of web applications, and every four years, the community releases the OWASP Top 10 report, which outlines the most pressing security concerns for web applications. We’ll look at these vulnerabilities through the lens of a PHP developer, but they are relevant to building applications in any programming language.
The 2021 OWASP Top 10 list features ten of the most dangerous security vulnerabilities for web applications. If we compare the current list to the 2017 list, we can see that some security flaws remain in the list but are in a different place, and a couple of new security flaws are on the list as well.
Below is a table comparing the lists from 2017 and 2021. (The security flaws that were introduced to the 2021 list are outlined in bold, and the rest are just reshuffled.)
This table suggests that the majority of the security flaws that target web applications don’t change. What changes is the approach of developers when they attempt to fix these flaws. Contrary to a popular belief, avoiding these security flaws is rather easy to begin with; we just have to know a couple of basic rules applicable to a specific security issue.
Let’s dig into each of these security issues.
According to the 2021 edition of OWASP, the issue we should be paying the most attention to is broken access control. Broken access control is just what it sounds like: it occurs when the way we control access to our applications is flawed. An example of broken access control is pictured below.
Do you see the problem? The code is simply checking whether the username and password fields are not empty. What about running a couple of queries in the database to ensure that the username and password exist? To verify the account in question? That part has been conveniently forgotten about. A user can simply put anything in the username and password fields to ensure they’re not empty, click Submit, and the user will be logged in.
To avoid broken access control issues: always verify the username (email) and password fields against the database before flagging the user as logged in.
Cryptographic failures were previously known as “sensitive data exposure”. Sensitive data exposure was renamed to “cryptographic failures” because this addresses a number of security problems, while “sensitive data exposure” addresses only one of them.
Cryptographic failures cover the failure of encrypting data, which often leads to sensitive data exposure. Cryptographic failures in PHP are mostly related to passwords: hashing them with anything other than hashing algorithms that were designed to be slow (think BCrypt and Blowfish) is a cryptographic failure, because other types of hashes (MD5 and similar) are easy and quick to bruteforce.
To avoid cryptographic failures: ensure that all of the passwords stored in your database are hashed with an algorithm that’s slow to bruteforce. We suggest you choose Blowfish or BCrypt, as these algorithms are safe for long-term use, have been tested by security experts, and have been proven to withstand attacks.
If you have a lot of users using your application, you might also want to look into salting. For large numbers of hashes, salts slow down the cracking process.
Injection is the most frequently discussed security issue on the Web. Everyone has heard of it: pass user input to a database, and you have an injection flaw. Injection attacks are relatively simple to overcome, but they’re still a problem due to the sheer amount of applications connected to databases.
The image below depicts a relevant code example.
The flaw shown above is pretty self-explanatory: when any user input is passed on to a database, anyone can do whatever crosses their mind. This flaw is not exclusive to PHP. If you pass user input straight into a database using any other programming language, and you’ll have exactly the same problem.
The consequences of a successfully mounted SQL injection attack can range widely, but in most cases, they span the following things:
Both of these actions, if performed successfully, will be detrimental to any business. A database dump taken of the user table will result in it being sold on the dark Web, and once it sells and the attacker makes a profit, other attackers will use the data to mount credential stuffing attacks. An attacker gaining administrative rights to a database that stores user data will also result in havoc — not just for site users, but for the site owners, who’ll be hit with a storm of negative public scrutiny.
To avoid SQL injections: use PDO with parameterized queries. Such an approach protects applications against SQL injection, because the data is sent separately from the query itself.
Such an approach to the query shown earlier would look as pictured below (notice the changes in lines 13 and 14).
Insecure design, on the other hand, differs from injection and has a separate category. Injection is part of insecure design, but insecure design isn’t injection. Insecure design covers how code is written by design (that is, by default). This means that if, by default, your code passes any of the user input to a database, or if it allows users to log in without authenticating themselves, or if it allows them to upload files without checking their extensions, or if it returns user input without validating it, you have an insecure design flaw.
To avoid SQL injection, passing user input to a database, and insecure design flaws, ensure that you follow secure coding guidelines outlined by OWASP or other vendors. If you follow these guidelines, you should be safe on this front.
In the fifth and sixth spots, we have security misconfiguration and outdated components. These two flaws are different from those mentioned previously, but they’re also very dangerous.
When probing an application for a possible security misconfiguration vulnerability, attackers will look at everything. They’ll attempt to access default accounts, access pages that should be protected, exploit unpatched vulnerabilities, and so on. Our only hope in this scenario is for the components to be updated and patched against all kinds of vulnerabilities. Outdated components often come with nasty vulnerabilities which, if exploited, can result in a database being leaked and sensitive data being exposed, servers going down, reputations lost, fines being issued, and so on.
That’s why it’s vital to always do the following:
To avoid misconfigurations and outdated component flaws: ensure that you’re using updated components and that your code follows basic security standards such as those mentioned above.
For your application to be more secure, pay close attention in particular to the components that let users authenticate themselves.
Identification and authentication failures were previously known as the “Broken Authentication” vulnerability. Such a vulnerability occurs when an application doesn’t adequately protect the part of itself that lets users authenticate themselves, which could mean one or more of the following things:
To avoid identification and authentication failures: make sure the register and login forms are built securely. Of course, that’s easier said than done, but follow the steps outlined below, and you should be good to go:
While issues related to the logging and monitoring mechanism are relatively self-explanatory, software and integrity failures may not be. There’s nothing magical about this, though: the OWASP community is simply telling us that we should verify the integrity of all kinds of software we’re using, be it PHP-based or not. Think about it: when was the last time you updated your application? Did you verify the integrity of the update? What about the assets you load into your web application?
Take a look at the code example pictured below. Do you notice anything?
Integrity is everywhere. And while in some situations a violation of integrity will provide warnings (as in the image above), in other cases the consequences will be more severe and can lead to a data breach.
To make sure your code hasn’t been tampered with, it’s critically important to properly monitor your infrastructure, but such an approach can itself be flawed. When your approach to monitoring is flawed, you won’t catch errors. Some errors are small, like the one shown above. Some errors are more severe, such as when your application is vulnerable to SQL injection, security misconfiguration, or any other of the other flaws listed above. So always make sure that your application is logging any anomalies related to the critical functionality of your website.
Doing so is easier said than done, but employing software that monitors the entire perimeter of your website for unauthorized, security-related events is an excellent place to start. Unfortunately, monitoring everything manually is only feasible when your application is rather small, but it won’t get you far in the long run.
To mitigate software and integrity failures, and logging and monitoring issues: look into web application firewall offerings such as those offered by Cloudflare, Sucuri, or Imperva. And remember: paying security vendors is always cheaper than recovering from a data breach.
The final important issue in the 2021 OWASP Top 10 list is server-side request forgery (SSRF). SSRF is an attack that allows a nefarious party to send requests to a website through a vulnerable server. SSRF is a new vulnerability in the OWASP list, and it acts similarly to its CSRF cousin. While CSRF aims to make unintended requests on behalf of the user, SSRF aims at the server. SSRF forces an application to make requests to the location set by the attacker. Look at the piece of code pictured below. (Note that the call to the
header()function should be completed before any text is written into the page, as otherwise the call might be ignored.)
This piece of code does a couple of things. It first checks whether the URL provided in the
picture_urlGET parameter is a valid URL. It then provides the content in the URL to the user, and redirects the user to another PHP script. Providing the content in the URL to the user is precisely what makes this PHP code susceptible to SSRF. Displaying anything provided by the user is dangerous, because a user can do any of the following things:
Avoiding SSRF: Arguably, the easiest way to avoid such an attack is to employ a whitelist of URLs that can be used. A whitelist in a PHP web application would look something along the lines of the code pictured below. (Notice particularly lines 25 to 28.)
Now the application echoing the output of the URL back to the user is no longer a problem, since the list of URLs is controlled by you. Your application is no longer vulnerable to SSRF!
In this article, we’ve walked you through the top ten security flaws that could compromise your PHP web applications. Some of these flaws entered OWASP for the first time in 2021, and others have been reshuffled from the older 2017 edition of OWASP. However, one principle remains the same: all of them are relatively dangerous and should be dealt with appropriately.
Hopefully you’ve found this article useful for improving the security of your applications. To dive deeper, I recommend you immerse yourself in the world of OWASP to learn more about how to best secure your web applications.
Lukas is an ethical hacker and frequent conference speaker. Since 2014, he's found and responsibly disclosed security flaws in some of the most visited websites in Lithuania. He runs one of the biggest and fastest data breach search engines in the world, BreachDirectory.com, frequently speaks at conferences, and writes in multiple places including BreachDirectory and his personal blog at lukasvileikis.com.
© 2000 – 2023 SitePoint Pty. Ltd.