PHP: Security issues FdSc Module 109 Server side scripting and Database design 2011
Rule Number One Never, Ever, Trust Your Users Assume: Every single piece of data your site collects from a user contains malicious code Always That includes data you think you have checked with client-side validation, for example using JavaScript because JavaScript can be disabled The data may not be coming from your form
SQL injection Using a security hole to run SQL queries on a database Typical login query: $check = mysql_query("SELECT Username, Password FROM Users WHERE Username = '".$_POST['username']."' and Password = '".$_POST['password']."'"); If the entered user name is ' OR 1=1 # then a different query is run
SQL injection SELECT Username, Password FROM Users WHERE Username = '' OR 1=1 #' and Password = '‘ This will return all the user names and passwords from the database! The first entry is likely to be the admin user!! How does this work? The # symbol tells MySQL that what follows is a comment, so it won’t execute As 1 always = 1 it evaluates as TRUE, so the OR part is TRUE and the statement effectively becomes: SELECT Username, Password FROM Users
SQL injection - solution mysql_real_escape_string This escapes special characters in a string Escaping in PHP means that you place a \ in front of a character so that it is interpreted as text and not a command It will escape: \x00 \n \r \ ‘ “ \x1a
SQL injection - solution function make_safe($variable) { $variable = mysql_real_escape_string(trim($variable)); return $variable; } This will escape command characters and remove excess space characters $username = make_safe($_POST['username']); Makes the unsafe '' OR 1=1 #' become '\' OR 1=1 #' and very few people have a username of \' OR 1=1 #
Password protection Passwords must not be stored in clear text They must be protected by hashing Hash algorithms turn any amount of data into a fixed- length checksum that cannot be reversed hash("hello") = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1 fa7425e73043362938b9824 hash("hbllo") = 58756879c05c68dfac9866712fad6a93f8146f337 a69afe7dd238f3364946366 if the input changes by even a tiny bit, the resulting hash is COMPLETELY different
Password protection The password is hashed and stored in the database. At no point is the unhashed user's password ever stored When the user attempts to login, the hash of the password they entered is checked against the hash in the database. If the hashes match, the user is granted access. If not, the user is told they entered an incorrect password.
Password protection Hashed passwords are not secure Dictionary or brute force Try words or combinations until a match is found Lookup table Store each word:hash pair from a dictionary and then compare each hash Rainbow table A combination of lookup table and brute force
Password protection Top 10 passwords in 180,00 (hacked file) 123456 12345678 qwerty abc123 12345 monkey 111111 consumer letmein
Password protection Use a “salt” to add additional protection A salt is a string of random characters that gets appended to the password before hashing If the password is 123456, the hash is known If the password is 123456Uwqe2uXdSKpAA the hash is not known
Password protection The way it works is: Generate a long random salt Hash the password joined to the salt Save the hash and the salt in the database. To validate a password: Get the hash and salt for that user from the database. Compute the hash of the password they tried to login with joined with the salt Compare the two If they are EXACTLY the same, then the password is valid. If there is any difference, then the password is invalid.
Password protection Practical example using SHA (no salt) SHA() creates a one way encrypted string of exactly 40 characters Define the password field in a user table as CHAR(40) Assume a users table with fields for userID, firstname, lastname and password
Password protection Syntax: INSERT INTO users (firstname, lastname, password) VALUES ('Arthur', 'Smith', SHA('password'); SELECT userID FROM users WHERE firstname = 'Arthur' AND password = SHA('password');
Password protection To use a salt investigate: AES_ENCRYPT ('password', 'salt') AES-DECRYPT ('password', 'salt')
Input validation Firstly: Check that something has been entered Secondly Make sure it is the right type
Input validation Use the empty() function to check for a blank entry if(empty($_POST['userName'])==FALSE ) { $userName = $_POST['userName']; } else echo 'Username is not set'; exit();
Numeric validation Rating is required to be number between 1 and 5 is_numeric checks it is a number <?php if(isset($_POST[“lRating"])) { $number = $_POST[“Rating"]; if((is_numeric($number)) && ($number > 0) && ($number < 6)) echo "Selected rating: " . $number; // Write the rating to the database here } else echo "The rating has to be a number between 1 and 5!"; ?>
Cross site scripting The most basic form of cross site scripting (XSS) is to put some JavaScript in user- submitted content (eg a blog post or comment field) <SCRIPT>Dosomethingmalicious</SCRIPT> Steal the data in a user's cookie or session Use cookie and session data to impersonate the user
Cross site scripting The htmlentities function: <?php htmlentities($variable, ENT_QUOTES); ?> will convert HTML special characters into HTML literals So <STRONG>Bold Text</STRONG> normally displays as Bold Text But after using htmlentities displays as <STRONG>Bold Text</STRONG> which cannot be executed
Summary Security measures are: Counteract SQL injection Protect passwords Validate input Counteract cross site scripting Marks available in assignment 2 Validation techniques used (5%) Security methods implemented (5%)