Fugitive Thought

Login | Register | RSS | Help

Safer PHP

small logo

Safer PHP

By Justin

I do basic PHP coding for money as I'm going through college. My job description labels me as a PHP/MySQL database front end designer, which basically boils down to "hey, we have a website that we think would be done best with a database..... write it!! :-)". While I am not and do not make any claim to being a professional in PHP nor MySQL nor security, I have learned quite a few tricks of the trade and this set of tutorials in Safer PHP is designed to impart this knowledge unto you. I have poked around the Internet and looked at some of the tutorials that explain how to do the same things that I am going to explain here. But every one I have looked at has some security issue with it. In this set of tutorials, I am going to run through the design and creation of some basic forms and features and explain from a security aspect why the code is written as it is.

I assume that if you are looking at this PHP tutorial that you have a functional knowledge of HTML, including web forms. I also assume that you have had some introduction to PHP and MySQL, althought you don't need to be a 1337 coder by any means to use and understand what I'm writing.


Entry #1: Secure Password Authentication


Part 1: The Login Page

One of the first uses that came to my mind when I started learning PHP was "Hey, I can use this to make secure parts of sites that only people with the password can get to!!". While I understand that I could achieve a rudimentary equivalent to this using a simple .htaccess file for authentication, PHP provides expandibility. By this I mean that I can display different content to different people based on which username is logged in and PHP makes such rudimentary administrative functions as changing passwords much simpler and seamless from a web-based standpoint.

There are three parts to a password system. You have to have a way to create the password and / or add the user in the first place. Then you have to have a way to log into the system using this username / password. Then you have to have some way for the site to remember that the user is logged in so it can continue to show the user their personalized or secure content until they log out or close the browser. Well this system is a bit of a loop because you probably want to password protect the page that can set and change passwords so that no random user can just load that page and mess with everyone elses accounts.

Rather than getting lost in the loop of where to start, I'm going to begin where you as a user would begin: the login page. The login page is also the simplest part of the system. All you need is a very basic HTML page with a form on it like this:

			<html>
				<head>
					<title>Login - Enter Username and Password</title>
				</head>
				
				<body>
					<center>
						<form method="post" action="login.php">
							Username:<br>
							<input type="text" name="username"><br>
							Password:<br>
							<input type="password" name="password"><br>
							<input type="submit" value="Log In">
						</form>
					</center>
				</body>
			</html>
		
Which renders to look like this:
Username:

Password:

As you can see from reading the form HTML code, this form will pass the text the user enters on to a file named "login.php". Therefore, the logical next step is to describe and write login.php.


Part 2: The Login Script

The login script (login.php) has been passed two variables from the HTML form. These variables can be accessed in two ways. The stanard method in PHP now, and the way I have seen used the most is simply to reference the variable name as if it was declared here. This method is simply to read $username and $password for the data. Unfortunately, this is not a necessarily secure method of accessing the data. If I enter the URL login.php?username=justin&password=myreallysecretpassword, then justin is put into $username and 'myreallysecretpassword' is put into $password as well. The only way to ensure that we are getting the username and password enterred from the form is to to read the POST data variable. So whenever we want to find out what the user enterred for a username, we look at the variable $_POST['username'] and whenever we want to check what they enterred for a password, we check $_POST['password']. While this is simply a technicallity and not really a security hole, it ensures that the site responds to exactly what the user enterred in those fields and helps to provide a clean experience.

Another tip for using any sort of data taken from a user form is to secure the data before you use it. I will explain this in greater detail later, but the part of the code that says:

			$username = htmlspecialchars(stripslashes($_POST['username']), ENT_QUOTES);
		
is removing and encoding any potentially insecure strings to keep them from accidentally being translated into a MySQL query.

This being said, here is my code for login.php:

	<?php
		// Connect to the database - note, you will have different login information!!
		$server   = "localhost";		// Server connecting to
		$username = "justin";			// Username to connect to the database server
		$password = "somepassword";		// Password to connect to the database server
		$database = "users";			// Database that contains the table we need
		mysql_connect($server, $username, $password);		// Connects to the server
		mysql_select_db($database);		// Sets it so we're using the proper database

		// Strip and encode the username properly
		$username = htmlspecialchars(stripslashes($_POST['username']), ENT_QUOTES);
		
		// Search the table containing info for this username
		$query = "SELECT * FROM `Accounts` WHERE `Username`='".$username."'";
		$result = mysql_query($query));
		if(mysql_num_rows($result) == 0)
		{
			// No entries matching this username in the database...
			die("Sorry, Invalid Username / Password!");
		} 
		else 
		{
			// Set flag so we only run through the loop once
			$done = "";
			$valid = false;
		
			// Get the password hash associated with that username
			while($done != "done" && $row = mysql_fetch_assoc($result))
			{
				// Get the salt used in the password
				$salt = substr($row['Password'],0,8);		// Salt used in hashing the password
				$hash = substr($row['Password'],8);			// The actual hash of the salt + password
				
				// Use the found salt to get the hash of the password the user entered
				$password = mhash(MHASH_SHA256, $salt.$_POST['password']);
				
				$valid = ($password == $hash);
				
				// Flag that we've already checked once, don't go through loop again 
				// even if there are more entries for this username (not recommended)
				$done = "done";
			}
			
			// If it wasn't valid, inform user
			if($valid == false)
			{
				die("Sorry, Invalid Username / Password!");
			}
			
			// Otherwise it's valid so set up the session
			else
			{
				// Generate a random set of characters to ID the session
				
			}
		}
	?>
		

About Us | Site Map | Privacy Policy | Contact Us | ©2006 Justin DeMaris & Steven Maresca