There is an error in my original ensure_password_requirements. The line:
PHP Code:
$authInfo['password'] = hash($authInfo['hash'], $authInfo['salt'] . $pw);
should be:
PHP Code:
$authInfo['password'] = hash($authInfo['hasher'], $authInfo['salt'] . $pw);
Note the key 'hash' should be 'hasher'.
Other than that, the sample code doesn't produce the error I'm seeing on your sample page:
Parse error: syntax error, unexpected $end in /home/sikuneh/public_html/includes/users/validateLogin.php on line 42
That error could be caused by a missing close curly bracket, or by improper use of short tags (mostly, using them when short tags are disabled, which they aren't on the free servers). Please post the block of code (up to the outermost "{}") that contains line 42 and mark that line with a comment. Better still, use an editor that supports auto-indenting and paren highlighting (e.g. emacs, Notepad++, Eclipse) to figure out where the missing token might be.

Originally Posted by
atlanis

Originally Posted by
Alex Mac
Would that be vulnerable to session hacking? They can just change $_SESSION['logged'] to 1 and then they'll be able to access your hidden content.
Yes it would.
As far as I've seen, only the session ID is vulnerable, since it's the one thing that is supplied by (and available to) clients. A hacker can try to steal a user's session ID or pick one at random and send that as their own ID, or try to force a user to use a particular ID. All other session data is only accessible to server processes, which means other local users could potentially read it, but not web users under normal circumstances. Local users shouldn't have read access on a properly secured server, but if they do, session data can be stored in a DB. Web users could only access session data if some script has appropriate vulnerabilities (file read or write, script injection), at which point the only way to prevent attacks is to close those vulnerabilities. Do you know of a way web users can read or write session data, or are you coding defensively against unknown vulnerabilities in the server or web scripts?

Originally Posted by
atlanis
I, of course, use different formulas on different sites. 'x32' is just a short random string to allow my script to separate the two parts of the validation. The 'x' character does not occur in a hexadecimal hash, so to someone with knowledge that will become apparent rather quickly.
Since hash functions have fixed length output, you could do away with the separator.
PHP Code:
//shared
$hashLen = array(
'sha256' => 64, 'sha224' => 64,
'sha512' => 128, 'sha384' => 128,
'whirlpool' => 256,
'tiger192,4', => 64,
//...
);
// exception codes
define('EXC_DB_ERROR', 1);
// so that the default hasher can be defined in exactly one place:
define('HASHER_DFLT', 'sha512');
function auth_hash($user, $salt, $pw, $hasher=HASHER_DFLT) {
return hash($hasher, $user . $salt . $pw);
}
/* creation & parsing of authentication data refactored as functions
rather than spread across multiple scripts to increase cohesion.
*/
function pack_authorization($username, $user_id, $password_hash, $salt, $hasher=HASHER_DFLT) {
$auth_hash = auth_hash($username, $salt, $password_hash, $hasher);
$auth_product = strlen($auth_hash . $salt) * intval($user_id);
return base64_encode($auth_hash . tostring($auth_product));
}
function unpack_authorization($data, $salt, $hasher=HASHER_DFLT) {
global $hashLen;
$validation_original = base64_decode($data);
/*
str_split below will split $validation_original into two pieces as long as:
digits(user_id)+digits(strlen(auth_hash . salt)) <= hashLen(hasher)
where digits(x) = floor(log10(x))+1 is the number of digits in x. Even with
64 bit integers, log(x, 10) < 21. Moreover, if there's overflow, PHP should
switch to floating point, in which case the length of the product as a string
will be limited by the precision, and the str_split should still work fine. Of
course, if there's overflow, then the $user_id calculation will be incorrect.
*/
list($auth_info['auth_hash'], $auth_product)= str_split($validation_original, $hashLen[$hasher]);
$auth_info['uid'] = $auth_product / strlen($auth_info['auth_hash'] . $salt);
return $auth_info;
}
function check_authorization($data, $salt, $hasher=HASHER_DFLT) {
$logged_in = false;
$auth_info = unpack_authorization($data, $salt, $hasher);
try {
$q = $db->prepare("SELECT username, password FROM users WHERE id = ? LIMIT 0,1;");
$q->execute(array($auth_info['uid']));
$row = $q->fetch(PDO::FETCH_ASSOC);
if ($auth_info['auth_hash'] == auth_hash($row['username'], $salt, $row['password'], $hasher)) {
$logged_in = true;
}
} catch (PDOException $exc) {
throw new RuntimeException("Internal database error.", EXC_DB_ERROR, $exc);
}
return $logged_in;
}
PHP Code:
// on successful login:
$_SESSION['validation'] = pack_authorization($username, $user_id, $password_hash, $salt));
PHP Code:
// to check login:
try {
$logged_in = check_authorization($_SESSION['validation'], $salt);
} catch (Exception $exc) {
switch ($exc->getCode()) {
case EXC_DB_ERROR:
// inform user & log error
...
break;
default:
// unknown/generic error
...
break;
}
}
The salt used in creating the authentication data better not be the same as that used for hashing passwords, as that would imply every password was hashed with the same salt (unless you also use the username as salt for the password hashes).
Still, this relies an awful lot on security through obscurity, which historically hasn't been very secure. If someone has access to session data, they probably have access to your script source.
Moreover, the above doesn't seem terribly useful. If an attacker has read-write access to session data, they can simply copy someone's authorization validation data (it doesn't even need to be the same). If they don't have write access, they won't be able to forge the data, so there's no point in checking that it's valid. Only if an attacker has write but not read access will it stymy them for a bit, in which case obscuring the user ID doesn't accomplish anything. It could be useful in reducing the possibility of an attacker successfully picking a valid random ID. Is that what you use it for?