Lately, I have been working on a project with a group of developers that I found. In this modern day, security is a must. You have people stealing your server information, database login details, user passwords, script insertions and more. Several years ago security wasn’t a big deal, but now is a desperate time, and desperate times call for desperate measures. Because of this, I have refined my knowledge of hacks that others can do and how to prevent them (or at least prevent most).
These days, it is necessary to encrypt your password in a database. Sure you may encrypt your password with md5 or sha1, but there are methods to decrypt these methods. A good concept is to “do multiple times,” and, in this case, do encryption multiple times. No, I do not mean to md5 twice. There are methods such as salting, or adding extra input to the encryption. One great method is to generate a secure hash on user registration or using information you may already know that the outside world may not, such as registration date (timestamp is best).
// User registration
$pass = md5($pass . sha1($pass . time()));
In the above example, we used two functions for encryption: md5 and sha1. It is usually best to use many methods of encryption such as above. Extremely few people know how to decrypt md5, and the same for sha1. Together, it is virtually impossible to figure it out. One other thing I want to point out is that we salt twice in that php above. First in sha1 using time(), and the second using the sha1 encryption in md5. The more secure the better, although do not overdo it. Please.
Limit Authorization in the Database
When installing an application, many users just use the default user settings for their database details. The user will have access to every permission in the DB that he can get (depending if on hosted domain or self managed server). If a hacker comes in and gets your details, you are really screwed because they have permission to delete any database, tables, rows, and columns, insert meaningless data, update current data with wrong details or worse. If you follow the password encryption method above, it would be difficult for one to decrypt your passwords.
The best thing to do if you are the installer is to verify which permissions you need in order to run the software correctly. On the other hand, if you are a programmer, please know which permissions, precisely, you need to have the program run without the disruption of errors.
Cross Site Request Forgeries
These are trickier than the above, though are really simple to prevent. In order to know if your software or web site can be hacked with CSRF’s, ask your self if it accepts $_GET or $_POST (or $_REQUEST). To portray how malicious this can be and no matter how secure your application is, Gmail was found to be vulnerable by CSRF’s. There was a method for seeing all the contacts a person had and more. If you have an online store, for example, someone can easily forge a request that the user has, like the following:
The above has several things wrong with it. First, it does not even check if the key ‘product_id’ exists. The second is that is uses $_REQUEST which is bad. This predefined, global variable built into the PHP core contains the values of $_GET, $_POST, and others depending on your php.ini configuration file. To forge a request one can easily alter the HTML using Firebug or any other tool in the browser, or outside the browser and save it, like so:
<img src="buy.php?product_id=5" alt="Welcome!" />
This is the best reason to just switch to $_POST when possible. By definition made by the W3C, POST should be used when an action is made and GET should be used to retrieve information. HINT: When you buy something, you are performing an action. You may also be thinking that CSRF’s also work with POST. Well, it does. What I do, and same for countless other applications, is to use form tokens. These basically hold some information of the user that requested the form. You may either simply md5 the user’s IP Address or a combination of other things, or store some information in the database with a unique token id. This token will be placed in the form as follows:
<input name="token" type="hidden" value="<?php echo generate_token(); ?>" />
if (isset($_POST['submit']) && !empty($_POST['product_id']))
if ($_POST['token'] == generate_token())
There are many great improvements here, especially one that we will discuss later on the article. IP Addresses can not be forged, atleast I do not think so. The truly best form of doing tokens is generating a completely new token based on time and other factors and inserting that into the database. When the form is submitted, you select the token from the DB and verify it from there. We now use $_POST and check if the form has been submitted and if the product id is not empty. If the form has been submitted, we then check if the two tokens are the same. A solution we will discuss later on is to cast the product_id into an integer since that is what it is supposed to be. This prevent SQL Injections.
Cross Site Scripting
alert('This page is not XSS-proof');
Imagine inputting that for a field that can be seen publicly like your username, full name, email address, and more. If you do not do the proper measures for preventing scripting, any user that visits a page containing the field in which the above is submitted will be notified that “This page is not XSS-proof.” The are several ways to prevent this script from being called. You can either remove the html tags or use html entities. I prefer using html entities:
//Check if the form has been submitted and that
// $_POST['username'] is not empty before continuing
$username = trim(htmlentities($_POST['username']));
This can lower your chances of being hacked using XSS significantly by converting <script> to <script> and other things like & to &
This last one is one of the most difficult since you have to do the same for every input you get that will go into the database. There really is not one justified method for preventing this. There are several and they do not protect against everything either, only most. If you ask someone for their usernameand password to login, a hacker who specializes in this may input something that can essentially modify your query.
$sql = 'SELECT username, password FROM users WHERE username=' . $_POST['username'];
With the above query, someone can easily input the following without quotes ‘foobar OR 1=1′. This query every user in the database with their username and password, because of the fact that 1 = 1 without even caring about the username being foobar. To prevent this you can do several meaningful things. Distinguish tables and columns from values using `, distinguish string values using “, escape using the database’s own escape function, and cast each value to what it is supposed to be. Here is the final product:
$sql = 'SELECT `username`, `password` FROM `users` WHERE `username`="' . mysql_real_escape_string($_POST['username']) . '"';
Although I did not present type casting in the above example (except in the last CSRF example), you can easily either do intval to whatever needs to be an integer and floatval for decimal numbers. Remember the tips explained above for SQL injections do not cover everything, and would be virtually impossible to prevent everything.
As a last note, I have explained how to prevent password hijacking, database corruption, CSRF and XSS attacks, and SQL injections. I hope you think of this tutorial every second you allow user input. With this guide, you will save yourself and any potential users headaches.