• (2 Pages)
  • +
  • 1
  • 2

User Authentication Class Rate Topic: ***** 4 Votes

#1 E_Geek  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 45
  • View blog
  • Posts: 236
  • Joined: 20-February 11

Posted 14 September 2011 - 01:51 PM

*
POPULAR

When I started out with PHP the first thing I wanted to create was an authentication system for any website I was wanting to create. I never took into account the fact these websites were going to be so bad nobody would visit them, I just wanted to create an authentication system. Nowhere could I find a straight forward answer to a nice, simple, secure PHP authentication system.

As time went by, and I learned a lot more about the language, as part of a learning exercise I set myself, I created the system I was looking for, and now, I'm creating the tutorial I was looking for all that time.

Prerequisites:
Knowledge of PHP 5.2+
Knowledge of Database Interaction (Interaction is not handled by this tutorial)
Basic knowledge of Object Orientated Programming (OOP) and PHP Classes
The ability to read, understand and think for yourself.

As listed within the Prerequisites, I will not handle any form of Database interaction in this tutorial, which could be viewed as more of a walk-through. There are two main reasons for this, 1, I use a PDO Database Wrapper I created, which would not show the full database queries, and 2, This is a tutorial for an authentication class, not database interaction.

Let's begin by discussing some of the security problems we are looking to negate by creating this authentication class. Now I'm a believer in using OOP, and distributing reusable code, why write something that's already been written? So instead of re-writing, I'm going to offer some links to better understand what we are trying to block. Please don't just skip past these links, it's important to fully understand what you're doing, before you start doing it.

Session Hijacking
Session Fixation
Rainbow Tables

Database Design

-- Table structure for table `users`
-- Holds user accounts
--
CREATE TABLE users (
id int(11) NOT NULL auto_increment,
email char(128) NOT NULL,
password char(128) NOT NULL,
user_salt varchar(50) NOT NULL,
is_verified tinyint(1) NOT NULL,
is_active tinyint(1) NOT NULL,
is_admin tinyint(1) NOT NULL,
verification_code varchar(65) NOT NULL,
PRIMARY KEY (`id`)
)


id – Used to told the unique identifier for each table row
email – holds the users email address
password – holds the hash of the users password
user_salt – contains the users salt value
**Non Essentials**
These fields are once I use, but you don't necessarily need to use.
is_verified – 0 or 1, holds whether the account has been verified
is_active 0 or 1, holds whether the account is active
is_admin 0 or 1, holds whether the account is an admin account
verification_code – holds the verification code for the user

-- Table structure for table `logged_in_member`
-- Holds members currently logged in
--
CREATE TABLE logged_in_member (
id int(11) NOT NULL auto_increment,
user_id int(11) NOT NULL, 
session_id char(32) binary NOT NULL, 
token char(128) NOT NULL,
PRIMARY KEY (`id`)
) 


id – Unique identifier of logged in member (can be used to count logins for display)
user_id - ID of user logged in
session_id – ID of users session
token – Users unique token

You will learn more about what each row is for as we move along.

Our authentication is going to be object-orientated, and we will use a class to hold all of our methods needed for this system.

<?php

class Auth {
	private $_siteKey;

	public function __construct()
  	{
		$this->siteKey = 'my site key will go here';
	}



A nice and simple start to our class. First, we have declared our class and gave it the name of Auth, we have told it their will be one class wide variable, called $_siteKey (the _ shows it is private, this is a naming convention, and is not required, but is good practise). We have used the private keyword, because we do not want any class extending this one (for whatever reason you would create one) to be able to access the siteKey.

The siteKey is the first of two salt's we will use in this authentication class, the second we will discuss later. Your siteKey can be anything you want it to be, and as a rule of thumb, the longer the better. I would say use at least 50 characters, and try to avoid the use of actual words or phrases. 'ddhue**2o' is better than 'banana'.

Next, we set our classes __construct() function. This function is automatically called every time our class is instantiated, so if we call $Authenticate = new Auth(); then the __construct() function is called. We will take advantage of this, and this is where we will set out site-wide salt. Your salt should be different for every web-application you use this class on, but should not be changed on any single website after deployment as it will 'break' all current accounts.

Next, we will create a method that will return a random alphanumeric string of the length we pass it. This method will be private, as it is designed for use in this class only. However, this is more of a 'utility' method, and if you wish, you may place it in another functions file (In projects, I normally have a file containing the 'bit-part' methods I use) and use it from that location, just be sure to include the file if you place it elsewhere.

private function randomString($length = 50)
{
	$characters = '0123456789abcdefghijklmnopqrstuvwxyz';
	$string = '';    
		
	for ($p = 0; $p < $length; $p++) {
		$string .= $characters[mt_rand(0, strlen($characters))];
	}
		
      	return $string;
}



When calling the function we pass if a $length value, which is defaulted to 50. This method will be called in our class when we are creating a users individual salt value, which you, the developer, will not even know. This is a fairly simple method, which iterates $length amount of times, adding a randomly selected character from the $characters string. (Feel free to add more characters into the array, there is no need to duplicate characters).

Next, we want to create a function which will Hash the data we pass it. We don't want to encrypt our passwords, as encryption is reversible, whereas a hash cannot be reversed. This is exactly what we need, as at no point do you need access to you user's passwords, and at no point should you be displaying these passwords (And at the same time, there is never a need to display the password hashes). If a user forgets their password, a new random password should be sent to them, insisting they change it upon login. Other sensitive data being stored in a database such as names and addresses should be encrypted.

As this method is designed for use only within this class, we want it to be private, with a name like hashData. We then want to pass it the parameter $data, which we want hashing.

Our function will simply return a hash_hmac of our data, I would strongly recommend using the sha512 hashing algorithm. Set the hash_hmac $key parameter to that of $this->_siteKey, to use the classes own siteKey value.

protected function hashData($data)
    	{
		return hash_hmac('sha512', $data, $this->_siteKey);
	}



Next we will create the function isAdmin, which we want to be public. This function will simply check the $_SESSION['user_id'] against it's database row, to check the value of the is_admin field. If it is 1, the function should return true, and we have an admin, if it is 0, the function should return false, as the user is not an admin. This function is not needed if you chose not to add the is_admin field to your database.

public function isAdmin()
{		
	//$selection being the array of the row returned from the database.
	if($selection['is_admin'] == 1) {
		return true;
	}
		
	return false;
}



Now we want to create a user, another public function which would be called from a registration script (My createUser function holds no validation of any kind, as I do this before calling this method.)

So go ahead and create a function which will be passed an email, a password and, if you opted to use the is_admin field, this function will also hold a parameter for is_admin (Mine holds a default as 0, meaning not an admin). Within this function, we want to create a $userSalt, by calling the randomString function and using it's return value as our users individual salt. The individual salt is created in case an attacker manages to access your siteKey. Next, we need to add a pinch of salt to our password. Here you have some options. You can simply prepend or append the salt onto the password parameter, or insert it into the middle (although remember how you add it for when we create a login method.) Once the salt has been added, we call our hashData method, passing it the salted password, and storing the return value, as this is our completed hashed password. If you chose to keep the verification code, also call the randomString function to create a verification code.

All of this data should then be committed to the database, not forgetting to also set your is_verified and is_active fields (I set defaults of 0 and 1, as I email the verification code to the user.).

Without any database work, your function should contain code resembling the following.

public function createUser($email, $password, $is_admin = 0)
{			
	//Generate users salt
	$user_salt = $this->randomString();
			
	//Salt and Hash the password
	$password = $user_salt . $password;
	$password = $this->hashData($password);
			
	//Create verification code
	$code = $this->randomString();

	//Commit values to database here.
	$created = …

	if($created != false){
		return true;
	}
			
	return false;
}



As for a return value, I simply return true if the user was created correctly, false otherwise. If you use the verification_code and is_verified, then you will also want to call sendVerification() to email a users verification code to them.

Login() comes next, which once again should be a public method. It's parameters should be $email and $password, which would be gathered from a login form. We will process the password in the same manner of creating it's hash, and check both values against our database.

First, use the given email to select the users row from the database, if it exists. If it doesn't, I return the integer 4, which I class as 'No Match'. If the row exists, we continue on to add the user_salt field to our password, in the same manner as we did when creating the account, and proceed to call our hashData method to hash the salted password. We then check whether the password hash matches the password hash in our database.

If you use the is_verified and is_active fields, your next step will be to check, one by one, whether their values are 0 or 1. If they are 0, I return 1 for not verified, and 2 for not active. If the user is both active and verified, we proceed to the next step.

This is where we utilize our second database table, and log our member in. So we need to create a token for our user. I do this by taking a random string, and concatenating it to the users http agent, and hashing the result. As follows:
	//First, generate a random string.
	$random = $this->randomString();
        //Build the token
	$token = $_SERVER['HTTP_USER_AGENT'] . $random;
	$token = $this->hashData($token);



Following the creation of the token, we want to set some session variables, but first we must start the session with session_start(). We want to set both the user's id and the token we have just generated. Then we proceed by removing any previous row the user may have in the logged_in table, and adding the new values into the logged_in_member table, using session_id() to gather the session id.

Once this is done, I return 0 if everything is successful, or 3 for 'Error Occurred', meaning everything matches fine, the user is active and verified, but an error is stopping them from logging in. In this case, I would call session_destroy() and ask the user to retry.

This method should resemble the following:

public function login($email, $password)
{
	//Select users row from database base on $email
	$selection = ...
		
	//Salt and hash password for checking
	$password = $selection[0]['user_salt'] . $password;
	$password = $this->hashData($password);
		
	//Check email and password hash match database row
		
	//Convert to boolean
	$is_active = (boolean) $selection['is_active'];
	$verified = (boolean) $selection['verified'];
		
	if($match == true) {
		if($is_active == true) {
			if($verified == true) {
				//Email/Password combination exists, set sessions
				//First, generate a random string.
				$random = $this->randomString();
				//Build the token
				$token = $_SERVER['HTTP_USER_AGENT'] . $random;
				$token = $this->hashData($token);
					
				//Setup sessions vars
				session_start();
				$_SESSION['token'] = $token;
				$_SESSION['user_id'] = $selection[0]['id'];
					
				//Delete old logged_in_member records for user
				
				//Insert new logged_in_member record for user
				$inserted = …

				//Logged in
				if($inserted != false) {
					return 0;
				} 
					
				return 3;
			} else {
				//Not verified
				return 1;
			}
		} else {
			//Not active
			return 2;
		}
	}
		
	//No match, reject
	return 4;
}



Our next function is one to check that a users session is legitimate upon each page request, so go ahead and call another public function checkSession(). As all of our information is stored within the session, we have no need to pass any parameters to this method.

This method will use $_SESSION['user_id'], which was set within the login method, to extract the row from logged_in_member. If no row exists, the method should return false, and a false return on the function call should result in a destroyed session and a redirect to the login page.

If the row exists, you should then check that session_id() and $_SESSION['token'] match their corresponding values in the database table. If they do, then we have the correct user, and we should call our refreshSession() method (Which hasn't been created yet, but we'll do that next.). Once the refresh has been called, and has returned true, we return true. If refreshSession() returns false, we should return false and ask the user to re-login, as they are vulnerable to session fixation.

public function checkSession()
{
	//Select the row
	$selection =  ...
		
		
	if($selection) {
		//Check ID and Token
		if(session_id() == $selection['session_id'] && $_SESSION['token'] == 				$selection['token']) {
			//Id and token match, refresh the session for the next request
			$this->refreshSession();
			return true;
		}
	}
		
	return false;
}



refreshSession() should be made private, as it will only be accessed from within our class. We need to regenerate our session id, recreate our token, change $_SESSION['token'] and update the users logged in table row. Without the database work, your method should resemble:

private function refreshSession()
{
	//Regenerate id
	session_regenerate_id();
		
	//Regenerate token
	$random = $this->randomString();
	//Build the token
	$token = $_SERVER['HTTP_USER_AGENT'] . $random;
	$token = $this->hashData($token); 
		
	//Store in session
	$_SESSION['token'] = $token;



Next we need a logout() function, which will be public. Even though we can call session_destroy() from anywhere, we have this method so we can remove the user's row from the logged_in_members table. And this is exactly what we will do. You can delete by session_id, token or user_id. I use all three although it is not necessary.

If you use the is_active and is_verified fields, you will want functions to check whether those fields are set to 0 or 1, and functions to change whether they are set to 0 or 1. These functions will accept $user_id as a parameter, in most cases will use $_SESSION['user_id'], but can also be used when listing all members within a admin area for easy management.

If you require the sendVerification($user_id) function, then create it public, so it can be used to resend verification, and it must require the $user_id parameter. This function should select the verification_code from the users table, dependant on $user_id, and use the mail function to send the mail. Something like so:

	//$email = users email taken from table
	$subject = 'Your verification code';
	$header = 'Sent by my website';
	$message = 'Your verification code is' . $verification_code;

	mail($email,$subject,$message,$header);



You also want a function to check your verification code. Say in your message you provided a link to www.mywebsite.com/verify.php?email=email&code=code, you would use $_POST to extract email and code, and pass them to checkVerification($email, $code); which would use the email to check whether the code is correct, if it is correct it would then set the users is_verified status to 1.

And that is our Auth class complete. If you have any trouble feel free to contact me through www.everythinggeek.co.uk, or ask for help on the almighty dreamincode.net forums. A simple change you could implement yourselves would be a function to extract the users email based on their user id, and to call this within the sendVerification() method.

To put this class to use, when a user navigates to a page that requires authentication, we begin by using session_start(), and instantiating out Auth class. First we use a simple check to see if $_SESSION['user_id'] is set, if it isn't we direct the user to the login page. If it is set, we use checkSession() to make sure the session is legitimate. If it isn't, we call logout() and ask the user to re-log, if i's legitimate, we allow the user access to the page.

<?php
require_once 'Classes/Auth.php';

session_start();

$auth = new Auth();

if (!isset($_SESSION['user_id'])) {
	//Not logged in, send to login page.
	header( 'Location: index.html' );
} else {
	//Check we have the right user
	$logged_in = $auth->checkSession();
	
	if(empty($logged_in)){
		//Bad session, ask to login
		$auth->logout();
		header( 'Location: index.html' );
		
	} else {
		//User is logged in, show the page
	}



For admin only pages, ontop of what we do on normal pages, we simply check if isAdmin() is true, if it isn't we don't allow any access.

	$admin = $auth->isAdmin();
		if($admin == true)
		{
			//User is admin, continue.
		} else {
			//User is not an admin
		}



To login, we gather the user's email and password from a login form, and pass it to Auth's login($email, $password) method, if it returns 0, we redirect to our logged in index page, otherwise we throw up an error.

To register, we have our registration form call createUser($email, $password) which returns true upon success. If we are registering an admin, we call the third parameter $is_admin = 1.

And we have success, a simple and secure authentication class written in PHP. As for the database side of things, I strongly suggest looking into PDO and MYSQLI (Major difference being PDO supports every database type, allowing for portability) and to use prepared statements, protecting against SQL injection. Feel free to contact me for help, more information or with any suggestions you may have, as I said this system is designed to be simple.

Is This A Good Question/Topic? 9
  • +

Replies To: User Authentication Class

#2 GodinHell  Icon User is offline

  • D.I.C Head

Reputation: 2
  • View blog
  • Posts: 51
  • Joined: 06-September 11

Posted 15 September 2011 - 08:47 AM

This is an Epic POst.

Thanks Thanks a lot :)
Was This Post Helpful? 0
  • +
  • -

#3 Jstall  Icon User is offline

  • Lurker
  • member icon

Reputation: 434
  • View blog
  • Posts: 1,042
  • Joined: 08-March 09

Posted 16 September 2011 - 05:52 AM

Very nice tutorial, congrats on getting it featured :).
Was This Post Helpful? 0
  • +
  • -

#4 jumanji  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 01-November 11

Posted 01 November 2011 - 02:46 PM

another great tuts!!! keep on posting!!!
Was This Post Helpful? 0
  • +
  • -

#5 Atli  Icon User is online

  • D.I.C Lover
  • member icon

Reputation: 3716
  • View blog
  • Posts: 5,975
  • Joined: 08-June 10

Posted 01 November 2011 - 07:58 PM

There is one issue in your randomString function.
$string .= $characters[mt_rand(0, strlen($characters))];


The mt_rand function includes the max param as a possible return value, so used like this there is a possibility that it will try to search one index to far. The last usable index in a 10 char string is 9. You'd want to use strlen($characters) - 1 to ensure you get a valid index.

I'm also wondering why your database "email" field is CHAR and your "user_salt" field is VARCHAR. Seems that should be the other way around. And emails can be up to 254 characters long, so a 128 char long field may not be enough. (Probably rare to find an email that long though, granted :))


Otherwise I like this. Especially how you use the "logged_in_member" table. I'm personally more inclined to put a "last_seen" timestamp in the users table itself and then just count WHERE last_seen > NOW() - INTERVAL X MINUTES to get an active user count, but your method adds some extra security.

Actually, come to think about it, how do you remove rows from it when users just leave without logging out? You don't seem to have any sort of timeout attached to it.
Was This Post Helpful? 1
  • +
  • -

#6 dallbee  Icon User is offline

  • New D.I.C Head

Reputation: 4
  • View blog
  • Posts: 15
  • Joined: 17-October 11

Posted 10 December 2011 - 04:25 PM

Despite your efforts to prevent session hijacking, This code still allows it to happen:

$token = $_SERVER['HTTP_USER_AGENT'] . $random;


HTTP_USER_AGENT can be forged rather easily. You're better off using an IP Address for salting. A user's IP address cannot be stolen unless the IP address somehow gets released to the DNS pool and a proxy server is made out of it, while a User agent can be stolen by simply grabbing it via the same $_SERVER['HTTP_USER_AGENT'] on a different webpage, and modifying the headers sent by your browser. A quick search on google provided http://mobiforge.com...her-config-file , a firefox addon that was made a while back to show proof of concept.
Was This Post Helpful? 0
  • +
  • -

#7 Atli  Icon User is online

  • D.I.C Lover
  • member icon

Reputation: 3716
  • View blog
  • Posts: 5,975
  • Joined: 08-June 10

Posted 11 December 2011 - 02:50 AM

The fact that the user agent can be switched quite easily doesn't really matter though. The token does not depend on the user agent being unknown, or unique, to work. Only the combined value of the user agent and the random number must be unpredictable, which it would be even if you left the user agent out entirely.


Also, while you may not be able to "steal" an IP Address from a user, there are ways to assume an address already in use. It's not as easy to do as choosing which user agent to send, but still. The IP Address is pretty much just another user supplied variable.
Was This Post Helpful? 0
  • +
  • -

#8 dallbee  Icon User is offline

  • New D.I.C Head

Reputation: 4
  • View blog
  • Posts: 15
  • Joined: 17-October 11

Posted 23 December 2011 - 05:50 PM

$string .= $characters[mt_rand(0, strlen($characters))];


You really think mt_rand with an invariable seed is unpredictable?
Was This Post Helpful? 0
  • +
  • -

#9 E_Geek  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 45
  • View blog
  • Posts: 236
  • Joined: 20-February 11

Posted 16 March 2012 - 01:25 PM

GodinHell, jumanji, Jstall - Thanks for the positive feedback :)

Atli - Thanks very much for the feedback. I've never stumbled upon an invalid index from the random string function, but I can see what you mean, thanks for pointing it out!
As for the database, it was very quickly decided upon, and you are right about the field types. In the version I use I have incorporated a time stamp within the session, And I will edit to reflect when I get chance to completely overview this tutorial.

dallbee - The HTTP_USER_AGENT doesn't entirely matter, it just adds a salt to the random value, and to be honest could be easily considered overkill. I know the user agent is easily forged, but the fact is the random string can not be easily forged. To make things a bigger pain in the arse for an attacker, one could easily use the ip address and user agent, or forgo them completely and use two random strings.

As for your suggestion that mt_rand is predictable, I would assume you have some solid backing? Refreshing your browser on This Page will show that mt_rand is perfectly viable for it's purpose in this class.

If you can offer me evidence otherwise, please do, I am always on the look-out for ways to improve my knowledge.
Was This Post Helpful? 0
  • +
  • -

#10 dallbee  Icon User is offline

  • New D.I.C Head

Reputation: 4
  • View blog
  • Posts: 15
  • Joined: 17-October 11

Posted 16 March 2012 - 04:02 PM

E_Geek,

Perhaps you misunderstand how a pseudo random generator works. If you know the seed, and you know the algorithm, you can produce the same result every time. If you give a Mersenne Twister algorithm a seed of 5 and it generates say...30, you will continue to get 30 each time that you supply a seed of 5. Your image that you posted for me demonstrates little more than the fact that a different seed creates a different gaussian distribution.

I did not say that mt_rand was predictable, I said that mt_rand with an invariable seed was predictable. At first sight that shouldn't be a problem. Since php 4.2, seeding has been done automatically when php is started up http://php.net/manua...ction.srand.php . There's a problem with that. The PHP implementation of mt_rand uses unix timestamp as its only source of entropy for the mt_rand seed. It's entirely known to an attacker. And thats only ONE of the problems with using mt_rand. tl;dr? mt_rand is NOT cryptographically secure. You can read more at: http://www.securitea...5FP0220OAE.html .

So now you've got a hash being done on a predictable salt, using sha512. That's still generally considered fairly secure, except when you realize that computing gets dramatically faster over time. md5 has extensive rainbow tables available for common salts. If the salt you want to lookup isn't available, it doesn't take all that long to generate an md5 rainbow table from scratch with a decent machine. Don't believe me? Buy one of these: http://www.digilenti...l.cfm?NavPath=2,400,819&Prod=GENESYS , and implement MD5 on it. You'd be amazed how fast you can compute hashes when you can get multiple operations into a single clock cycle. For now sha512 is secure, but its just a matter of time before resources get better.

All of this is easily solved by using a unique, and preferably unpredictable salt.

I realize how nitpicky this is, but its tutorials like this where many PHP programmers learn. Some of those programmers may never look further into security, or simply assume that the solution posted here is perfect. As such it is important that the security in the tutorial is top notch, particularly in light of how well written the tutorial is. You've done a great job and I'd simply like to see this detail modified in the tutorial.
Was This Post Helpful? 2
  • +
  • -

#11 Atli  Icon User is online

  • D.I.C Lover
  • member icon

Reputation: 3716
  • View blog
  • Posts: 5,975
  • Joined: 08-June 10

Posted 16 March 2012 - 04:55 PM

View Postdallbee, on 16 March 2012 - 11:02 PM, said:

All of this is easily solved by using a unique, and preferably unpredictable salt.

Is there a better method to generate a unique salt that you would recommend? Perhaps some other random number generator you would use?

I was playing around with the /dev/urandom file on Unix. Do you think this would be a sufficiently secure function?
/**
 * Generates a random hash. Only works on Unix systems!
 * @param string $algo [Optional] The output algorithm. Defaults to SHA512.
 * @return string
 */
function getRandomHash($algo="sha256") {
	if (is_readable("/dev/urandom")) {
		$fh = fopen("/dev/urandom", "r");
		if ($fh) {
			$data = fread($fh, 128);
			fclose($fh);
			return hash($algo, $data);
		}
	}
	return false;
}


Was This Post Helpful? 0
  • +
  • -

#12 dallbee  Icon User is offline

  • New D.I.C Head

Reputation: 4
  • View blog
  • Posts: 15
  • Joined: 17-October 11

Posted 16 March 2012 - 10:38 PM

Provided a shared hosting account isn't being used, /dev/urandom is a very secure way of grabbing a salt. I fully approve. =]
Was This Post Helpful? 0
  • +
  • -

#13 E_Geek  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 45
  • View blog
  • Posts: 236
  • Joined: 20-February 11

Posted 17 March 2012 - 07:09 AM

Hey, thanks for getting back to me :)

I agree with you that as a learning resource this should be reliable, and I now see you're point in its entirety, I will edit this to reflect in the near future.

I'm curious as to what method you would use in the circumstances? More notably for those who are using a shared hosting account ?
Was This Post Helpful? 0
  • +
  • -

#14 urieal  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 2
  • Joined: 21-April 09

Posted 19 March 2012 - 05:29 AM

View PostE_Geek, on 17 March 2012 - 07:09 AM, said:

Hey, thanks for getting back to me :)

I agree with you that as a learning resource this should be reliable, and I now see you're point in its entirety, I will edit this to reflect in the near future.

I'm curious as to what method you would use in the circumstances? More notably for those who are using a shared hosting account ?

Couldn't you use something akin to what is described here

$salt = bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM));

That should give you a fairly random salt of 256 bits, though, it also doesn't fix your issue using shared hosting :(
PS: Thanks for an excellent tutorial, very very very much appreciated...as well as for great additional comments from dallbee and Atli.
Was This Post Helpful? 0
  • +
  • -

#15 dallbee  Icon User is offline

  • New D.I.C Head

Reputation: 4
  • View blog
  • Posts: 15
  • Joined: 17-October 11

Posted 19 March 2012 - 11:36 AM

uriel,

The function you mentioned is essentially identical, the only difference being that the constant is already loaded so its faster than doing a file read. As far as fixing this for shared hosting, you could attempt to find other sources of entropy, but at that point there's no real reason to. Shared hosting has far more easily exploitable vulnerabilities.
Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2