Skip to content

Instantly share code, notes, and snippets.

@AmauryCarrade
Last active March 24, 2017 10:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AmauryCarrade/0a4abdaeaa0545e5ee02866759e2ef13 to your computer and use it in GitHub Desktop.
Save AmauryCarrade/0a4abdaeaa0545e5ee02866759e2ef13 to your computer and use it in GitHub Desktop.
Migration de FluxBB vers BCrypt
diff --git a/include/common.php b/include/common.php
index 1661f58..3af340a 100644
--- a/include/common.php
+++ b/include/common.php
@@ -45,6 +45,16 @@ if (!defined('PUN'))
exit;
}
+// If the password config is missing, here are some default values
+if (!isset($password_hash_options) || empty($password_hash_options))
+{
+ $password_hash_options =
+ [
+ 'algorithm' => PASSWORD_DEFAULT,
+ 'cost' => 12
+ ];
+}
+
// Load the functions script
require PUN_ROOT.'include/functions.php';
diff --git a/include/functions.php b/include/functions.php
index a014699..bfbc00a 100644
--- a/include/functions.php
+++ b/include/functions.php
@@ -27,7 +27,7 @@ function check_cookie(&$pun_user)
$now = time();
// If the cookie is set and it matches the correct pattern, then read the values from it
- if (isset($_COOKIE[$cookie_name]) && preg_match('%^(\d+)\|([0-9a-fA-F]+)\|(\d+)\|([0-9a-fA-F]+)$%', $_COOKIE[$cookie_name], $matches))
+ if (isset($_COOKIE[$cookie_name]) && preg_match('%^(\d+)\|([^|]+)\|(\d+)\|([0-9a-fA-F]+)$%', $_COOKIE[$cookie_name], $matches))
{
$cookie = array(
'user_id' => intval($matches[1]),
@@ -163,8 +163,11 @@ function authenticate_user($user, $password, $password_is_hash = false)
$result = $db->query('SELECT u.*, g.*, o.logged, o.idle FROM '.$db->prefix.'users AS u INNER JOIN '.$db->prefix.'groups AS g ON g.g_id=u.group_id LEFT JOIN '.$db->prefix.'online AS o ON o.user_id=u.id WHERE '.(is_int($user) ? 'u.id='.intval($user) : 'u.username=\''.$db->escape($user).'\'')) or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
$pun_user = $db->fetch_assoc($result);
- $is_password_authorized = pun_hash_equals($password, $pun_user['password']);
- $is_hash_authorized = pun_hash_equals(pun_hash($password), $pun_user['password']);
+ $is_password_authorized = check_password($password, $pun_user);
+
+ // The PHP password hash functions (i.e. bcrypt) donesn't support hash comparison directly.
+ // Not a real problem—in the source code, $password_is_hash is always false.
+ $is_hash_authorized = false; //pun_hash_equals(pun_hash($password), $pun_user['password']);
if (!isset($pun_user['id']) ||
($password_is_hash && !$is_password_authorized ||
@@ -1209,6 +1212,91 @@ function check_csrf($token)
}
+
+//
+// Hashes a password.
+// Never use pun_hash to hash passwords. Like, never.
+//
+function hash_password($plaintext_password)
+{
+ global $password_hash_options;
+ return password_hash($plaintext_password, $password_hash_options['algorithm'], $password_hash_options);
+}
+
+//
+// Checks if the given password is correct for an user.
+// This will also upgrade the password if needed on the fly, and update the hash in $user.
+//
+function check_password($plaintext_password, &$user)
+{
+ if (empty($user['password'])) return false;
+
+ global $password_hash_options;
+
+ $authorized = false;
+ $need_rehash = false;
+
+ // If there is a salt in the database we have upgraded from 1.3-legacy though haven't yet logged in
+ if (!empty($user['salt']))
+ {
+ if (pun_hash_equals(sha1($user['salt'].sha1($plaintext_password)), $user['password'])) // 1.3 used sha1(salt.sha1(pass))
+ {
+ $authorized = true;
+ $need_rehash = true;
+ }
+ }
+
+ // It must be md5 from 1.2
+ else if (strlen($user['password']) == 32)
+ {
+ if (pun_hash_equals(md5($plaintext_password), $user['password']))
+ {
+ $authorized = true;
+ $need_rehash = true;
+ }
+ }
+
+ // This must be SHA1 from the 1.4+ version
+ else if (strlen($user['password']) == 40)
+ {
+ if (pun_hash_equals($user['password'], pun_hash($plaintext_password)))
+ {
+ $authorized = true;
+ $need_rehash = true;
+ }
+ }
+
+ // This is a good password hashed using password_hash from PHP 5.5+.
+ else
+ {
+ $authorized = password_verify($plaintext_password, $user['password']);
+ $need_rehash = password_needs_rehash($user['password'], $password_hash_options['algorithm'], $password_hash_options);
+ }
+
+ // If the password should be re-hashed (and it was the good one, of course), we save a new one.
+ if ($authorized && $need_rehash)
+ {
+ update_password($plaintext_password, $user);
+ }
+
+ return $authorized;
+}
+
+//
+// Updates the password of the given user.
+// Updates the hash in $user too.
+//
+function update_password($plaintext_password, &$user)
+{
+ $password_hash = hash_password($plaintext_password);
+
+ global $db;
+ $db->query('UPDATE '.$db->prefix.'users SET password=\''.$db->escape($password_hash).'\''.((isset($user['salt']) && !empty($user['salt'])) ? ', salt=NULL' : '') . ' WHERE id='.$user['id']) or error('Unable to update user password', __FILE__, __LINE__, $db->error());
+
+ $user['password'] = $password_hash;
+}
+
+
//
// Try to determine the correct remote IP-address
//
diff --git a/lang/French/mail_templates/activate_password.tpl b/lang/French/mail_templates/activate_password.tpl
index 9a94c90..fc09206 100644
--- a/lang/French/mail_templates/activate_password.tpl
+++ b/lang/French/mail_templates/activate_password.tpl
@@ -2,7 +2,7 @@ Subject: Demande de nouveau mot de passe
Bonjour <username>,
-Vous avez demandé un nouveau mot de passe associé à votre compte sur les forums de <base_url>. Si vous n'en avez pas fait la demande ou ne souhaitez finalement pas le modifier, veuillez ignorer ce message. Il ne sera changé que si vous vous rendez à la page d'activation ci-dessous.
+Vous avez demandé un nouveau mot de passe associé à votre compte sur les forums de <base_url>. Si vous n'en avez pas fait la demande ou ne souhaitez finalement pas le modifier, veuillez ignorer ce message. Il ne sera changé que si vous vous rendez à la page d'activation ci-dessous.
=======================================================================
Votre nouveau mot de passe est : <new_password>
=======================================================================
@@ -10,6 +10,8 @@ Votre nouveau mot de passe est : <new_password>
Afin de modifier votre mot de passe, merci de vous rendre à la page suivante :
<activation_url>
---
+Nous vous recommandons vivement de changer ce nouveau mot de passe (dans « Mon profil », « Changer de mot de passe ») et de supprimer ce courriel, pour des raisons de sécurité.
+
+--
<board_mailer>
-(Veuillez ne pas répondre à ce message. Merci !)
\ No newline at end of file
+(Veuillez ne pas répondre à ce message. Merci !)
diff --git a/lang/French/mail_templates/welcome.tpl b/lang/French/mail_templates/welcome.tpl
index ec67f0b..24377a3 100644
--- a/lang/French/mail_templates/welcome.tpl
+++ b/lang/French/mail_templates/welcome.tpl
@@ -8,6 +8,8 @@ Mot de passe : <password>
Veuillez vous rendre à <login_url> pour activer votre compte.
---
+Nous vous recommandons vivement de changer le mot de passe qui a été généré (dans « Mon profil », « Changer de mot de passe ») par un mot de passe que vous seul(e) connaissez, et de supprimer ce courriel, pour des raisons de sécurité.
+
+--
<board_mailer>
-(Veuillez ne pas répondre à ce message. Merci !)
\ No newline at end of file
+(Veuillez ne pas répondre à ce message. Merci !)
diff --git a/login.php b/login.php
index 2d0aa80..c4d7c86 100644
--- a/login.php
+++ b/login.php
@@ -32,38 +32,7 @@ if (isset($_POST['form_sent']) && $action == 'in')
$result = $db->query('SELECT * FROM '.$db->prefix.'users WHERE '.$username_sql) or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
$cur_user = $db->fetch_assoc($result);
- $authorized = false;
-
- if (!empty($cur_user['password']))
- {
- $form_password_hash = pun_hash($form_password); // Will result in a SHA-1 hash
-
- // If there is a salt in the database we have upgraded from 1.3-legacy though haven't yet logged in
- if (!empty($cur_user['salt']))
- {
- $is_salt_authorized = pun_hash_equals(sha1($cur_user['salt'].sha1($form_password)), $cur_user['password']);
- if ($is_salt_authorized) // 1.3 used sha1(salt.sha1(pass))
- {
- $authorized = true;
-
- $db->query('UPDATE '.$db->prefix.'users SET password=\''.$form_password_hash.'\', salt=NULL WHERE id='.$cur_user['id']) or error('Unable to update user password', __FILE__, __LINE__, $db->error());
- }
- }
- // If the length isn't 40 then the password isn't using sha1, so it must be md5 from 1.2
- else if (strlen($cur_user['password']) != 40)
- {
- $is_md5_authorized = pun_hash_equals(md5($form_password), $cur_user['password']);
- if ($is_md5_authorized)
- {
- $authorized = true;
-
- $db->query('UPDATE '.$db->prefix.'users SET password=\''.$form_password_hash.'\' WHERE id='.$cur_user['id']) or error('Unable to update user password', __FILE__, __LINE__, $db->error());
- }
- }
- // Otherwise we should have a normal sha1 password
- else
- $authorized = pun_hash_equals($cur_user['password'], $form_password_hash);
- }
+ $authorized = check_password($form_password, $cur_user);
if (!$authorized)
$errors[] = $lang_login['Wrong user/pass'];
@@ -89,7 +58,7 @@ if (isset($_POST['form_sent']) && $action == 'in')
$db->query('DELETE FROM '.$db->prefix.'online WHERE ident=\''.$db->escape(get_remote_address()).'\'') or error('Unable to delete from online list', __FILE__, __LINE__, $db->error());
$expire = ($save_pass == '1') ? time() + 1209600 : time() + $pun_config['o_timeout_visit'];
- pun_setcookie($cur_user['id'], $form_password_hash, $expire);
+ pun_setcookie($cur_user['id'], $cur_user['password'], $expire);
// Reset tracked topics
set_tracked_topics(null);
@@ -175,7 +144,7 @@ else if ($action == 'forget' || $action == 'forget_2')
$new_password = random_pass(12);
$new_password_key = random_pass(8);
- $db->query('UPDATE '.$db->prefix.'users SET activate_string=\''.pun_hash($new_password).'\', activate_key=\''.$new_password_key.'\', last_email_sent = '.time().' WHERE id='.$cur_hit['id']) or error('Unable to update activation data', __FILE__, __LINE__, $db->error());
+ $db->query('UPDATE '.$db->prefix.'users SET activate_string=\''.hash_password($new_password).'\', activate_key=\''.$new_password_key.'\', last_email_sent = '.time().' WHERE id='.$cur_hit['id']) or error('Unable to update activation data', __FILE__, __LINE__, $db->error());
// Do the user specific replacements to the template
$cur_mail_message = str_replace('<username>', $cur_hit['username'], $mail_message);
diff --git a/profile.php b/profile.php
index ee0e3c8..c3df5df 100644
--- a/profile.php
+++ b/profile.php
@@ -96,25 +96,15 @@ if ($action == 'change_pass')
$result = $db->query('SELECT * FROM '.$db->prefix.'users WHERE id='.$id) or error('Unable to fetch password', __FILE__, __LINE__, $db->error());
$cur_user = $db->fetch_assoc($result);
- $authorized = false;
-
- if (!empty($cur_user['password']))
- {
- $old_password_hash = pun_hash($old_password);
-
- if ($cur_user['password'] == $old_password_hash || $pun_user['is_admmod'])
- $authorized = true;
- }
+ $authorized = $pun_user['is_admmod'] || check_password($old_password, $cur_user);
if (!$authorized)
message($lang_profile['Wrong pass']);
- $new_password_hash = pun_hash($new_password1);
-
- $db->query('UPDATE '.$db->prefix.'users SET password=\''.$new_password_hash.'\''.(!empty($cur_user['salt']) ? ', salt=NULL' : '').' WHERE id='.$id) or error('Unable to update password', __FILE__, __LINE__, $db->error());
+ update_password($new_password1, $cur_user);
if ($pun_user['id'] == $id)
- pun_setcookie($pun_user['id'], $new_password_hash, time() + $pun_config['o_timeout_visit']);
+ pun_setcookie($pun_user['id'], $cur_user['password'], time() + $pun_config['o_timeout_visit']);
redirect('profile.php?section=essentials&amp;id='.$id, $lang_profile['Pass updated redirect']);
}
@@ -193,7 +183,7 @@ else if ($action == 'change_email')
}
else if (isset($_POST['form_sent']))
{
- if (pun_hash($_POST['req_password']) !== $pun_user['password'])
+ if (!check_password($_POST['req_password'], $pun_user))
message($lang_profile['Wrong pass']);
// Make sure they got here from the site
diff --git a/register.php b/register.php
index f7a0bbc..e433d73 100644
--- a/register.php
+++ b/register.php
@@ -176,10 +176,11 @@ if (isset($_POST['form_sent']))
$now = time();
$intial_group_id = ($pun_config['o_regs_verify'] == '0') ? $pun_config['o_default_user_group'] : PUN_UNVERIFIED;
- $password_hash = pun_hash($password1);
+ $password_hash = hash_password($password1);
// Add the user
$db->query('INSERT INTO '.$db->prefix.'users (username, group_id, password, email, email_setting, timezone, dst, language, style, registered, registration_ip, last_visit) VALUES(\''.$db->escape($username).'\', '.$intial_group_id.', \''.$password_hash.'\', \''.$db->escape($email1).'\', '.$email_setting.', '.$timezone.' , '.$dst.', \''.$db->escape($language).'\', \''.$pun_config['o_default_style'].'\', '.$now.', \''.$db->escape(get_remote_address()).'\', '.$now.')') or error('Unable to create user', __FILE__, __LINE__, $db->error());
+ //'
$new_uid = $db->insert_id();
if ($pun_config['o_regs_verify'] == '0')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment