In this video tutorial I create an extremely secure PHP Login Script. If you didn’t watch part 20 of this tutorial, you should check it out to find out how to use PHP Sessions and Cookies.
To make this login secure I added all of the following security features:
Keep all user information stored on the server with Sessions
Run all input through very strict Regular Expressions
Regenerate a new session token every time the user updates sensitive information
I add a few additional tricks along the way. All of the code follows the video. If you have any ideas on how I could improve this script pass them along.
Code From the Video
Goodlogin.php Script
<?php
// Initialize a session.
session_start();
require_once(“./includes/confighamdb.php”);
?>
<?php
if (isset($_POST[‘submitted’])) { // Check if the form has been submitted.
if (preg_match (‘%^[A-Za-z0-9]\S{8,20}$%’, stripslashes(trim($_POST[‘userid’])))) {
$u = escape_data($_POST[‘userid’]);
} else {
$u = FALSE;
echo ‘<p><font color=”red” size=”+1″>Please enter a valid User ID!</font></p>’;
}
// FIX IT Check for a good password
if (preg_match (‘%^[A-Za-z0-9]\S{8,20}$%’, stripslashes(trim($_POST[‘pass’])))) {
$p = escape_data($_POST[‘pass’]);
} else {
$p = FALSE;
echo ‘<p><font color=”red” size=”+1″>Please enter a valid Password!</font></p>’;
}
// FIX IT PHP Code for the CAPTCHA System
$captchchk = 1;
require_once(‘./includes/recaptchalib.php’);
$privatekey = “privatekey”;
$resp = recaptcha_check_answer ($privatekey,
$_SERVER[“REMOTE_ADDR”],
$_POST[“recaptcha_challenge_field”],
$_POST[“recaptcha_response_field”]);
if (!$resp->is_valid) {
// What happens when the CAPTCHA was entered incorrectly
In part 6 of my PHP Security video tutorial I cover a ton of ways hackers attack and how to hold them off. If you missed previous tutorials please watch them first. Here is the first one PHP Security.
In this specific tutorial I will cover:
How Spammers take over Comment Boxes
The Dangers of Providing Access to your Insert, Delete and Update SQL Querys
How Hackers use include and require to attack your site
The Damage that can be Done by Directory Traversal
In part 3 of my PHP Security video tutorial I go over the most vulnerable ways hackers attack websites. I focus a lot on authentication and client side attacks. Specifically I go over the tools and techniques used to:
Crack user ids and passwords
Catch and manipulate data sent from the browser to the server
Cheat encryption techniques
Down load and change how websites secure themselves
Cheat forgotten password scripts into giving up passwords
In this PHP Security Video tutorial I continue to show you how hackers break into web applications and how to better secure your site. If you missed part 1 of this tutorial definitely watch it first here PHP Security.
Specifically in this tutorial I will show you how SQL Injection works. Don’t do this on any site that you don’t own! I then go over all of the following:
Limit What Hackers can Enter in your Input Fields
Create Encrypted Activation Codes
Validate Input Data
Verify Email Addresses
How to Act Abnormally and Confound Hackers
All of the code follows the video. If you have any other questions or comments leave them below. Feel free to use the code however you like, but I’m not stating that it is 100% secure. The fact is all code can eventually be cracked. The goal is to make the code so complicated that hackers just give up and move on to an easier target.
Code From the Video
Register.PHP Code
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Strict//EN”
if (isset($_POST[‘submitted’])) { // Handle the form.
if (preg_match (‘%^[A-Za-z\.\’ \-]{2,15}$%’, stripslashes(trim($_POST[‘first_name’])))) {
$fn = escape_data($_POST[‘first_name’]);
} else {
$fn = FALSE;
echo ‘<p><font color=”red” size=”+1″>Please enter your first name!</font></p>’;
}
// Check for a last name.
if (preg_match (‘%^[A-Za-z\.\’ \-]{2,30}$%’, stripslashes(trim($_POST[‘last_name’])))) {
$ln = escape_data($_POST[‘last_name’]);
} else {
$ln = FALSE;
echo ‘<p><font color=”red” size=”+1″>Please enter your last name!</font></p>’;
}
// Check for an email address.
if (preg_match (‘%^[A-Za-z0-9._\%-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$%’, stripslashes(trim($_POST[’email’])))) {
$e = escape_data($_POST[’email’]);
} else {
$e = FALSE;
echo ‘<p><font color=”red” size=”+1″>Please enter a valid email address!</font></p>’;
}
// Check for a street.
if (preg_match (‘%^[A-Za-z0-9\.\’ \-]{5,30}$%’, stripslashes(trim($_POST[‘street’])))) {
$s = escape_data($_POST[‘street’]);
} else {
$s = FALSE;
echo ‘<p><font color=”red” size=”+1″>Please enter your street address!</font></p>’;
}
// Check for a city.
if (preg_match (‘%^[A-Za-z\.\’ \-]{2,25}$%’, stripslashes(trim($_POST[‘city’])))) {
$c = escape_data($_POST[‘city’]);
} else {
$c = FALSE;
echo ‘<p><font color=”red” size=”+1″>Please enter a valid city!</font></p>’;
}
// Check for a state.
if (preg_match (‘%^(A[KLRZ]|C[AOT]|D[CE]|FL|GA|HI|I[ADLN]|K[SY]|LA|M[ADEINOST]|N[CDEHJMVY]|O[HKR]|PA|RI|S[CD]|T[NX]|UT|V[AT]|W[AIVY])$%’, stripslashes(trim($_POST[‘state’])))) {
$st = escape_data($_POST[‘state’]);
} else {
$st = FALSE;
echo ‘<p><font color=”red” size=”+1″>Please enter a valid state!</font></p>’;
}
// Check for a zip code.
if (preg_match (‘%^[0-9]{5}$%’, stripslashes(trim($_POST[‘zip’])))) {
$z = escape_data($_POST[‘zip’]);
} else {
$z = FALSE;
echo ‘<p><font color=”red” size=”+1″>Please enter a valid 5 digit zip code!</font></p>’;
}
// Check for a phone number.
if (preg_match (‘%^([0-9]( |-)?)?(\(?[0-9]{3}\)?|[0-9]{3})( |-)?([0-9]{3}( |-)?[0-9]{4}|[a-zA-Z0-9]{7})$%’, stripslashes(trim($_POST[‘work_phone’])))) {
$ph = escape_data($_POST[‘work_phone’]);
} else {
$ph = FALSE;
echo ‘<p><font color=”red” size=”+1″>Please enter a valid phone number!</font></p>’;
}
// Check for a password and match against the confirmed password.
if (preg_match (‘%\A(?=[-_a-zA-Z0-9]*?[A-Z])(?=[-_a-zA-Z0-9]*?[a-z])(?=[-_a-zA-Z0-9]*?[0-9])\S{6,}\z%’, stripslashes(trim($_POST[‘password1’])))) {
if ($_POST[‘password1’] == $_POST[‘password2’]) {
$p = escape_data($_POST[‘password1’]);
} else {
$p = FALSE;
echo ‘<p><font color=”red” size=”+1″>Your password did not match the confirmed password!</font></p>’;
}
} else {
$p = FALSE;
echo ‘<p><font color=”red” size=”+1″>Please enter a valid password!</font></p>’;
}
if ($fn && $ln && $e && $p && $fn && $s && $c && $st && $z && $ph) {
$query = “SELECT user_id FROM users WHERE email=’$e'”;
$result = mysql_query($query) or trigger_error(“Sorry email is taken”);
echo ‘<br /><br /><h1>Thank you for registering! A confirmation email has been sent to your address. Please click on the link in that email in order to activate your account.</h1>’;
exit();
} else {
echo ‘<p><font color=”red” size=”+1″>You could not be registered due to a system error. We apologize for any inconvenience.</font></p>’;
}
} else {
echo ‘<p><font color=”red” size=”+1″>That email address has already been registered. If you have forgotten your password, use the link to have your password sent to you.</font></p>’;
<p><b>State:</b> <input type=”text” name=”state” size=”2″ maxlength=”2″ value=”<?php if (isset($_POST[‘state’])) echo $_POST[‘state’]; ?>” /> <small>Use only the two letter initials</small></p>
<p><b>Password:</b> <input type=”password” name=”password1″ size=”20″ maxlength=”20″ /> <small>Use only letters and numbers. Must be between 4 and 20 characters long.</small></p>
<?php
// Define these as constants so that they can’t be changed
DEFINE (‘DBUSER’, ‘mysqladm’);
DEFINE (‘DBPW’, ‘password’);
DEFINE (‘DBHOST’, ‘localhost’);
DEFINE (‘DBNAME’, ‘hamdb’);
if ($dbc = mysql_connect (DBHOST, DBUSER, DBPW)) {
if (!mysql_select_db (DBNAME)) { // If it can’t select the database.
// Handle the error.
trigger_error(“Could not select the database!<br />MySQL Error: ” . mysql_error());
exit();
} // End of mysql_select_db IF.
} else {
// Print a message to the user, and kill the script.
trigger_error(“Could not connect to MySQL!<br />MySQL Error: ” . mysql_error());
exit();
}
// A function that strips harmful data.
function escape_data ($data) {
// Check for mysql_real_escape_string() support.
// This function escapes characters that could be used for sql injection
if (function_exists(‘mysql_real_escape_string’)) {
global $dbc; // Need the connection.
$data = mysql_real_escape_string (trim($data), $dbc);
$data = strip_tags($data);
} else {
$data = mysql_escape_string (trim($data));
$data = strip_tags($data);
}
This tutorial is a continuation of my Web Design and Programming Tutorial, but if you’re are well versed in PHP you should understand everything I present here.
I specifically will show you how to:
Hide your database access files
How to eliminate code injection with regular expressions
Introduce a bunch of PHP functions that will delete harmful code