Protect against SQL injections and brute-force attacks with password hashing

Time to Read: 10 minutes Difficulty Level: Beginner
Tools Needed: FTP access, PHPmyadmin Last Updated: 06/11/2018

Security

We all talk about it, read about it in the news, and worry about it. Every day websites are defaced, accounts hijacked and service providers bombarded with traffic aimed at knocking them offline. In this article I will go over two of the most common attack vectors that might be used against your website or service, starting with passwords.

One of the primary causes of data compromises is down to poor passwords, not only with regards to your login for your work-station, but for use online as well. I’m not going to cover how essential it is to ensure your passwords are strong and secure because that has been well-publicised elsewhere. However, to push the point home, I would like to direct you to https://howsecureismypassword.net/. My current workstation password takes 63 quintillion years to crack, but a password that I have come across in real life via a friend, would be cracked instantly, and is in the top 600 worst passwords. Just food for thought.

SQL Injections
Escape input
Restrict access
Prepared statements
Brute-force attacks

SQL Injections

The main topic of this guide is a method of attack that is often referred to, understood by few, but will have devastating consequences should it happen to you. To explain the problem, I’m going to run through a hypothetical situation.

A PA is asked by her manager to go to a boutique florist to pick up some flowers for the office. The manager always orders the same set of bouquets, so has printed off several order forms in advance. The manager gives the PA a signed order and sends her off. The thing is, the PA would really like some roses for her house, so she appends a note on the bottom saying “Please append a dozen red roses to this order, to be charged to the company account”. When the florist reads the order, they have no idea the amendment wasn’t authorised or written by the PA, so goes ahead and adds the roses. In this situation, the PA has inserted, or injected, an unauthorised addition to the request.

This, in essence, is a technique called SQL injection. An attacker will look for any way possible to interfere with the data that passes between your front end website and the database in the back end, where the content is stored. By injecting code into these requests, they can do anything from increasing credits in an account, displaying all the information of users or customers, or at worst, deleting the entire database. SQL injection is a major problem in the industry, and was ranked #1 in the The Open Web Application Security Project’s 2013 vulnerability list. Two of the biggest names to fall fowl of this kind of attack were Sony, who in 2012 lost over a million users information, including plain-text passwords, and Yahoo also in 2012 lost 450,000 login credentials.

Escape input

So, you may be thinking, how can I guard myself, my customers and my bottom line from this threat? Well, firstly, you need to escape all user input. By this, any information going into your system, whether it is registration forms, URL parameters, uploaded files or searches all need to be cleaned and inspected for malicious extra information. For example, let’s say you have a search bar on your site that allows users to search for your articles by name.

The query would be stored (in the PHP file stored on the webserver) as:

SELECT `topic_id`, `topic_title`, `topic_description` FROM `topic_table` WHERE `topic_title` = '$the_text_the_user_entered'

where the variable $the_text_the_user_entered would contain the search entered by the user . The problem is that anyone could put something like “1’; SELECT * FROM `user_table` WHERE `1`=`1 ” into $the_text_the_user_entered. This would make the final query become:

SELECT `topic_id`, `topic_title`, `topic_description` FROM `topic_table` WHERE `topic_title` = '1'; SELECT * FROM `user_table` WHERE `1`=`1'

We have fed the original query with a bogus query, title being equal to the number 1, and have appended a lookup for all the data in the user table, which will return every entry, because 1 always equals 1. The best way to avoid this is to, in essence, ignore the single quotes in the variable $the_text_the_user_entered. By filtering out, or escaping, these quotes, we prevent anyone from executing queries we haven’t authorised.

In our manager and PA analogy, this would be like the manager laminating the order before she hands it to the PA. If the PA tries to write on the plastic or un-peel it to access the paper underneath, it will be blindingly obvious that the document has been tampered with.

Restrict access

Another great method to avoid injection attacks is to have different SQL users that only have access to specific tables and specific operations. When you make a query to a database, you have to provide a user to perform this request. In an ideal situation, you would have a user called “SearchUser”, for the example above, who can only see the contents of the topics table, but not see any other tables, or edit the content within topics. This way, even if a malicious query slips through the net, the user executing the query does not have the privileges to perform this devious task. The best part about having multiple SQL users, is that unless you have direct access to the database, it is nigh impossible to switch the user or elevate their privileges from inserted statements.

Prepared statements

Finally, there are prepared statements. This method of running queries from within your code is both simple to set up and very secure. In essence, you write your query, in full beforehand, using placeholders for where your data will go when the query will be run. When you want to execute the query, you load the prepared statement and bind your values to the placeholders. In this way, we hand over the sanitisation to the framework that we are running, to be done in the binding stage before the execution of the query. As most modern frameworks and database interfaces support prepared statements, we can rely on them executing SQL securely, regardless of what platform we are using.

Brute-force attacks

There is one practice that will not secure you against these threats, but will mitigate the potential damage they pose. Almost all systems store users, including user names, emails and passwords. The thing is, if your database is breached, your key concern will be the passwords. If they are stored as-is in the database, you will be exposing your customers and your reputation at great risk. The best approach is to avoid storing the passwords in plain-text (completely unaltered and completely visible), and instead store a password hash. A hash is a one-way mathematical operation on a piece of data. Once you have the hash of said data, it is impossible to work out what the original text was, without trying every single permutation of possible inputs.

In a perfect world, this would be enough to keep your passwords safe; who would have the time go through every password ever and see if that hash matches the one you are searching for? Well, computers have. A bog-standard desktop or laptop can go through millions of permutations in a second. For this reason, hashes that were secure 10 years ago, are not secure now. The method of testing every conceivable password against the hash of the one you are looking for is called a brute-force attack, because you are using the sheer power of a machine to bash away at a problem until you get the desired outcome, no matter how long it takes. So, to avoid this, you need to do two things: pick a good hashing algorithm and use a salt.

MD5 was the traditional algorithm of choice for passwords on the web, because it was well supported and secure at the time. However, as technology and computing power has improved, the strength of MD5 has not. For this reason, and the fact that some mathematical vulnerabilities have been found in the algorithm itself, it would be wise to choose a different option to hash your passwords. SHA-256, Whirlpool and Tiger-192 would all be good candidates, amongst many others.

Finally, adding a salt to the hashing of passwords significantly increases the cryptographic strength of the hash. A salt adds complexity to password; it can be seen as a password for the system itself. Remember brute-force attacks on passwords? In the process of brute-forcing a hash, an attacker will run through a lot of failed attempts, so they could make a table containing the guessed password and its hash. It takes a lot less time to browse through a table than run a hash. These are called rainbow tables, and that can cut down on how long it takes to crack a password. A hashing function will always give the same output, regardless of what computer you are on or website you are browsing, thus making rainbow tables a reliable tool for cutting down on computational time to crack a password. However, this can be thwarted by appending a set series of random characters to every password. If we have a hashed password where the password is “password”, you won’t find it on a rainbow table under the entry for “password”. Why? Because we added our salt before we hashed the password, so what it will actually be is “password55HSDFj7£694H!BWhtbyt*87665tyhBDSFjm£ntryt%rwh”. All we have to do is stick the salt on the end when we do our checks, and the database or the system we are using won’t know any different; it will still come back with either a true or false on the password being correct.

I hope this very brief overview of some of the vulnerabilities posing against databases has opened your eyes to the potential dangers of having them connected to the internet. If you are concerned with any of the issues raised in this article, feel free to get in touch with us, to chat about your current systems, and to see if Nublue can help.