For all too many enterprises, it is not until after a security violation has occurred that best practices in web security become a priority. I have seen time and time again how obscure the world of web development security problems can be to too many of my fellow programmers during my years working as an IT security professional.
An successful approach to threats to web security must be constructive and defensive, by definition. To that end, this post is intended to ignite a security mentality, ideally injecting a healthy dose of anxiety into the reader.
This guide focuses in particular on 9 popular and relevant web security pitfalls to be aware of, including advice on how to mitigate them. The emphasis is on the Top 9 Web Vulnerabilities found by the Open Web Application Protection Project (OWASP), an international non-profit organization that seeks to strengthen the security of software worldwide.
A little cyber security primer before we start – authentication and authorization
I sometimes experience an uncertainty about the difference between authorization and authentication when communicating with other programmers and IT professionals. And, of course, this widespread misunderstanding is exacerbated by the fact that the abbreviation auth is also used for both. This misunderstanding is so widespread that this problem should maybe be included as “Common Web Vulnerability Zero” in this article.
So before we proceed, let’s clarify the distinction between these two terms
Authentication: Verifying that a person is (or at least appears to be) a particular user since their security credentials have been correctly provided by him/her (password, answers to security questions, fingerprint scan, etc.).
Authorization: Ensuring that a specific user has access to a particular resource or is allowed to conduct a specific action.
In other words, authentication is knowing who an entity is, while authorization is knowing what can be accomplished by a given entity. Let’s dig into the top 10 problems with internet protection with this in mind.
Common Web Security Mistake
1: Injection flaws
A classic failure to filter untrusted input results in injection flaws. When you transfer unfiltered information to the SQL server (SQL injection), the browser (XSS, we’ll talk about this later), the LDAP server (LDAP injection), or anywhere else, it can happen. The problem here is that these entities can be injected with commands by the attacker, resulting in data loss and browser hijacking of clients.
Everything from untrusted sources that your application receives must be screened, ideally according to a whitelist. As having that right is very difficult and generally easy to circumvent, you can almost never use a blacklist. Stellar examples of failing blacklists are usually provided by antivirus software devices. Matching with trends does not work.
Prevention: The good news is that it is “simply” a matter of correctly filtering the data and worrying about whether an input can be trusted to defend against injection. “But the bad news is that, unless it can be unquestionably believed, all input needs to be carefully filtered (but the expression “never say never” comes to mind here).
For example, successfully filtering 999 of them is not sufficient in a system with 1,000 inputs, as this still leaves one field that can act as the Achilles heal to bring down your system. And you may think it’s a good idea to place a SQL query result in another query, as the database is trusted, but if the perimeter is not, the feedback comes indirectly from malintent men. This, in case you’re interested, is called Second Order SQL Injection.
Since filtering is very difficult to do correctly (like crypto), what I generally advise is to focus on the filtering functions of your framework: they are known to work and are thoroughly scrutinized. If you don’t use frameworks, you really need to think hard about whether, in your server security context, not using them really makes sense. 99% of the time, it doesn’t.
2: Broken Authentication
This is a collection of multiple issues that can emerge during broken authentication, but not all of them stem from the same root cause.
I advise against believing that anyone really wants to roll out their own authentication code in 2014 (what do you think??). It’s incredibly difficult to get correct, and, just to name a few, there are a number of potential pitfalls:
- The URL can contain the session ID and leak it to someone else in the referrer header.
- Passwords can not be encrypted in storage or in transit, either.
- Session IDs can be predictable, so access is trivial.
- Fixing a session may be feasible.
- Session hijacking may be feasible, timeouts may not be correctly enforced or HTTP (no SSL security), etc…
Prevention: Using a framework is the easiest way to prevent this web security vulnerability. You may be able to correctly execute this, but it’s much simpler for the former. If you plan to roll out your own code, be highly paranoid and teach yourself what the pitfalls are. There are quite a few there.
3: Cross Site Scripting (XSS)
Prevention: There’s an easy solution for web security: don’t give the client HTML tags back. This has the added advantage of defending against HTML injection, a similar assault whereby the attacker injects plain HTML content (such as photos or noisy invisible flash players)-not high-impact but definitely irritating (“please stop it!”). This has the added benefit of defending against HTML injection. The workaround is typically simply to convert all HTML entities, so that
4: Insecure Direct Object References
This is a typical case of trusting user feedback in a subsequent security vulnerability and paying the price. A direct object reference means that an internal object is revealed to the user, such as a file or database key. The issue with this is that this reference can be given by the attacker and if permission is either not followed (or is broken), the attacker can access or do things from which they should be exempt.
The code has a download.php module, for example, which reads and allows the user to download files by using a CGI parameter to define the name of the file (for example, download.php?file=something.txt). The developer removed authorization from the code, either by accident or due to laziness. The intruder will now use this to retrieve any device files, such as the application code itself or any data left on the server, such as backups, that the user running PHP has access to. Uh-oh.-Uh-oh.
A password reset function that relies on user input to decide whose password we are resetting is another common vulnerability example. An attacker can only change the username field in the URL to say something like ‘admin’ after clicking the valid URL.
Incidentally, both of these examples are things that I have seen sometimes appearing ‘in the wild’ myself.
Prevention: Correctly and reliably execute user authorization, and whitelist the options. However, the whole issue can be avoided more often than not by storing data internally and not relying on it being transmitted via CGI parameters from the client. For this function, session variables in most frameworks are well suited.
5: Security misconfiguration
Web servers and applications that have been misconfigured are much more prevalent in my experience than those that have been properly configured. This could be because there is no lack of ways to mess things up. Only a few examples:
- Running the application in production with debugging allowed.
- A directory listing on the server that leaks useful information is allowed.
- Outdated Device Running (think WordPress plugins, old PhpMyAdmin).
- Getting unwanted services on the system working.
- Not modifying the default passwords and keys. (It happens way more often than you’d think!)
- Revealing error handling information, such as stack traces, to the attackers.
Prevention: Provide a successful “build and deploy” process (preferably automated), which can run tests on deployment. Post-commit hooks are the protection misconfiguration solution of the poor guy, to prevent the code from going out with built-in default passwords and/or create things.
6: Sensitive data exposure
This web security weakness deals with the defense of encryption and resources. Sensitive data at all times, including in transit and at rest, should be encrypted. No exceptions at all. Credit card data and user passwords can never move or be kept unencrypted, and it is always necessary to hash passwords. Obviously, the crypto/hashing algorithm must not be weak. Web security guidelines propose AES (256 bits and up) and RSA when in doubt (2048 bits and up).
And while it goes without saying that session IDs and sensitive information should not move in the URLs and that the safe flag should be on sensitive cookies, this is very important and can not be overemphasized.
Prevention: In transit: Use HTTPS with a proper certificate and PFSS with a proper certificate (Perfect Forward Secrecy). Over non-HTTPS links, do not accept anything. Have a safe cookie flag.
In storage: It’s tougher. You need to lower your exposure, first and foremost. Shred-it if you do not need confidential data. It’s not possible to steal data you don’t have. Don’t ever store credit card details, as you obviously don’t want to have to deal with PCI enforcement. Using a payment processor such as Stripe or Braintree to sign up. Second, store it encrypted and make sure that all passwords are hashed if you have confidential data that you really need. Usage of Bcrypt is recommended for hashing. Educate yourself on salting and rainbow tables if you don’t use Bcrypt.
And don’t store the encryption keys next to the secure data at the risk of stating the obvious. That’s like storing a lock on your bike that has a key in it. Secure your backups and keep your keys very safe with encryption. And don’t, of course, lose your keys!
7: Missing function level access control
This is simply an authorization failure. It means that when a function is called on the server, proper authorization was not performed. A lot of times, developers rely on the fact that the server-side generated the UI and they think that the functionality that is not supplied by the server cannot be accessed by the client. It is not as simple as that, as an attacker can always forge requests to the “hidden” functionality and will not be deterred by the fact that the UI doesn’t make this functionality easily accessible. Imagine there’s an /admin panel, and the button is only present in the UI if the user is actually an admin. Nothing keeps an attacker from discovering this functionality and misusing it if authorization is missing.
Prevention: On the server-side, authorization must always be done. Yes, always. No exceptions or vulnerabilities will result in serious problems.
8: Cross-Site Request Forgery (CSRF)
This is a nice example of a confused deputy assault whereby some other party tricks the browser into misusing its authority. For example, a 3rd party site may make the user’s browser abuse its authority to do something for the attacker.
In the case of CSRF, with your cookies/session, a third-party site issues requests to the target site (e.g., your bank) using your browser. For example, if you are logged in on one tab on the homepage of your bank and are vulnerable to this attack, another tab will make your browser abuse its credentials on behalf of the attacker, resulting in the confused issue of the deputy. The deputy is the browser that misuses its power to do what the intruder instructs him to do (session cookies).
Todd’s browser assumes that Alice links to an image while visiting Alice’s website, and immediately issues an HTTP GET request to fetch the image, but this simply instructs Todd’s bank to pass $1500 to Alice.
Incidentally, this example also shows altering the server state with an idempotent HTTP GET request that is itself a significant vulnerability in addition to showing the CSRF vulnerability. HTTP GET requests must be idempotent (safe), meaning they are unable to change the accessed resource. Never, ever, ever use idempotent strategies to modify the state of the server.
Fun fact: CSRF is also the strategy people used in the past for cookie-stuffing before affiliates were wiser.
Prevention: In a hidden field of a type that is inaccessible from the 3rd party platform, store a secret token. Of course, this hidden field still needs to be checked. Some sites still ask for your password when changing sensitive settings (such as, for example, your password reminder email), but I would suspect this is there to avoid abuse of your abandoned sessions (in an internet cafe for example).
9: Using components with known vulnerabilities
The title says everything. I will describe this again as more of a concern with maintenance/deployment. Do some testing, probably some auditing, before incorporating a new code. It may be very easy to use code that you obtained from a random individual on GitHub or any forum, but it is not without the possibility of a severe web security vulnerability.
For example, I have seen several instances where sites were owned (i.e., where an outsider gains administrative access to a system), not because the programmers were dumb, but because for years of development, a 3rd party software remained unpatched. For instance, with WordPress plugins, this happens all the time. If you don’t think your secret PHPMyAdmin installation would be found, let me introduce you to dirbuster.
The lesson here is that when the program is deployed, software development does not stop. Documentation, tests, and plans for how to manage and maintain it updated need to be available, particularly if it includes 3rd party or open-source components.
Prevention: Cautionary exercise. Do not be a copy-paste coder, beyond the apparent use of caution when using such components. Carefully check the piece of code you are about to bring into your program, as it could be disabled beyond repair (or, in some instances, purposely malicious, this way web security attacks are often unintentionally invited).
Remain up-to-date. Make sure that you use the newest versions of everything you trust and have a plan to periodically upgrade them. At the very least, subscribe to a newsletter about new product security vulnerabilities.
I hope that with this post I have managed to tickle your brain a little bit and to add a healthy dose of consciousness of paranoia and website security vulnerability.
The main takeaway here is that there are age-old coding practices for a cause and what existed back in the day for buffer overflows still applies in Python today for pickled strings. Security protocols help you write (more) the right programs that should be aspired to by all programmers.
Feedback on this post and its recommendations on mitigation are welcome and respected. Future related posts are planned, especially on the issue of security vulnerabilities for distributed denial-of-service (DDoS) and old-school (not web) IT. Please feel free to contact me directly at [email protected] if you have a specific request about what kind of site security to write about.