Notes
1. You will have to make core edits
2. You will have to re-make core edits after major Mybb updates
3. You need a minimum of PHP 5.5.0
4. If you would rather a plugin, you can useThis
Before you go any further!
MAKE A BACKUP OF YOUR DATABASE AND THE FILES YOU EDIT!
It's better to be safe than sorry.
First thing we want to do is see if you can use Bcrypt.
Open a new text document, Copy & Paste the below into it, save as cost.php, upload to your server and access it in a browser. If you have the minimum PHP version, It will spit out a number after a few seconds. Copy it, we will be using it later, you can then delete cost.php. If you do not have the minimum php version, you will have to update to 5.5.0 (or newer) and re-run cost.php.
PHP Code:
Code:
<?php
/**
*Thiscodewillbenchmarkyourservertodeterminehowhighofacostyoucan
*afford.Youwanttosetthehighestcostthatyoucanwithoutslowingdown
*youservertoomuch.8-10isagoodbaseline,andmoreisgoodifyourservers
*arefastenough.Thecodebelowaimsfor50millisecondsstretchingtime,
*whichisagoodbaselineforsystemshandlinginteractivelogins.
*/
if(PHP_VERSION_ID>=50500){
$timeTarget=0.05;//50milliseconds
$cost=8;
do{
$cost++;
$start=microtime(true);
password_hash("test",PASSWORD_BCRYPT,["cost"=>$cost]);
$end=microtime(true);
}while(($end-$start)<$timeTarget);
echo"AppropriateCostFound:".$cost;
}
else
{
echonl2br("Minimumrequirementnotmet!\nYourPHPversion:".PHP_VERSION."\nPHPversionneeded:5.5.0");
}
Edit: \inc\functions_user.php
Line: 73 - 189
Select the following:
PHP Code:
Code:
/**
*Checksapasswordwithasupplieduid.
*
*@paramint$uidTheuserid.
*@paramstring$passwordTheplain-textpassword.
*@paramarray$userAnoptionaluserdataarray.
*@returnboolean|arrayFalsewhennotvalid,userdataarraywhenvalid.
*/
functionvalidate_password_from_uid($uid,$password,$user=array())
{
global$db,$mybb;
if(isset($mybb->user['uid'])&&$mybb->user['uid']==$uid)
{
$user=$mybb->user;
}
if(!$user['password'])
{
$query=$db->simple_select("users","uid,username,password,salt,loginkey,usergroup","uid='".(int)$uid."'");
$user=$db->fetch_array($query);
}
if(!$user['salt'])
{
//Generateasaltforthisuserandassumethepasswordstoredindbisaplainmd5password
$user['salt']=generate_salt();
$user['password']=salt_password($user['password'],$user['salt']);
$sql_array=array(
"salt"=>$user['salt'],
"password"=>$user['password']
);
$db->update_query("users",$sql_array,"uid='".$user['uid']."'");
}
if(!$user['loginkey'])
{
$user['loginkey']=generate_loginkey();
$sql_array=array(
"loginkey"=>$user['loginkey']
);
$db->update_query("users",$sql_array,"uid=".$user['uid']);
}
if(salt_password(md5($password),$user['salt'])===$user['password'])
{
return$user;
}
else
{
returnfalse;
}
}
/**
*Updatesauser'spassword.
*
*@paramint$uidTheuser'sid.
*@paramstring$passwordThemd5()'edpassword.
*@paramstring$salt(Optional)Thesaltoftheuser.
*@returnarrayThenewpassword.
*/
functionupdate_password($uid,$password,$salt="")
{
global$db,$plugins;
$newpassword=array();
//Ifnosaltwasspecified,checkindatabasefirst,ifstilldoesn'texist,createone
if(!$salt)
{
$query=$db->simple_select("users","salt","uid='$uid'");
$user=$db->fetch_array($query);
if($user['salt'])
{
$salt=$user['salt'];
}
else
{
$salt=generate_salt();
}
$newpassword['salt']=$salt;
}
//Createnewpasswordbasedonsalt
$saltedpw=salt_password($password,$salt);
//Generatenewloginkey
$loginkey=generate_loginkey();
//Updatepasswordandloginkeyindatabase
$newpassword['password']=$saltedpw;
$newpassword['loginkey']=$loginkey;
$db->update_query("users",$newpassword,"uid='$uid'");
$plugins->run_hooks("password_changed");
return$newpassword;
}
/**
*Saltsapasswordbasedonasuppliedsalt.
*
*@paramstring$passwordThemd5()'edpassword.
*@paramstring$saltThesalt.
*@returnstringThepasswordhash.
*/
functionsalt_password($password,$salt)
{
returnmd5(md5($salt).$password);
}
/**
*Generatesarandomsalt
*
*@returnstringThesalt.
*/
functiongenerate_salt()
{
returnrandom_str(8);
}
Replace with:
PHP Code:
Code:
/**
*Checksapasswordwithasupplieduid.
*
*@paramint$uidTheuserid.
*@paramstring$passwordthemd5()'edpassword.
*@paramarray$userAnoptionaluserdataarray.
*@returnboolean|arrayFalsewhennotvalid,userdataarraywhenvalid.
*/
functionvalidate_password_from_uid($uid,$password,$user=array())
{
global$db,$mybb;
if(isset($mybb->user['uid'])&&$mybb->user['uid']==$uid)
{
$user=$mybb->user;
}
if(!$user['password'])
{
$query=$db->simple_select("users","uid,username,password,salt,loginkey,usergroup","uid='".(int)$uid."'");
$user=$db->fetch_array($query);
}
if(!$user['loginkey'])
{
$user['loginkey']=generate_loginkey();
$sql_array=array(
"loginkey"=>$user['loginkey']
);
$db->update_query("users",$sql_array,"uid=".$user['uid']);
}
if(strlen($user['password'])===32)
{
if(!$user['salt'])
{
if($password!==$user['password'])
returnfalse;
}
else
{
if(md5(md5($user['salt']).$password)!==$user['password'])
returnfalse;
}
$user['password']=salt_password($password);
$sql_array=array(
"salt"=>Bcrypt,
"password"=>$user['password']
);
$db->update_query("users",$sql_array,"uid='".$user['uid']."'");
return$user;
}
if(password_verify($password,$user['password'])||password_verify(md5($password),$user['password']))//UserCpdoesnotuseMD5,addMD5topassword_verifyforchangingpassword
{
return$user;
}
else
{
returnfalse;
}
returnfalse;
}
/**
*Updatesauser'spassword.
*
*@paramint$uidTheuser'sid.
*@paramstring$passwordthemd5()'edpassword.
*@paramstring$salt(Optional)Thesaltoftheuser.
*@returnarrayThenewpassword.
*/
functionupdate_password($uid,$password,$salt="")
{
global$db,$plugins;
//Createnewpassword
$user['password']=salt_password($password);
//Generatenewloginkey
$user['loginkey']=generate_loginkey();
$sql_array=array(
"salt"=>Bcrypt,
"password"=>$user['password'],
"loginkey"=>$user['loginkey']
);
$db->update_query("users",$sql_array,"uid='$uid'");
$plugins->run_hooks("password_changed");
return$user;
}
/**
*Bcryptpassword.
*
*@paramstring$passwordthemd5()'edpassword.
*@returnstringThepasswordhash.
*/
functionsalt_password($password)
{
$options=array('cost'=>11);
returnpassword_hash($password,PASSWORD_BCRYPT,$options);
}
/**
*DummyBcryptsalt
*
*@returnstringThesalt.
*/
functiongenerate_salt()
{
return'Bcrypt';
}
Edit: \inc\functions_user.php
Line: 173
Find the following and change the cost (default 11) to what cost.php gave you.
PHP Code:
Code:
$options=array('cost'=>11);
Edit: \inc\datahandlers\login.php
Line: 174 - 206
Select the following:
PHP Code:
Code:
if($strict==true)
{
if(!$this->login_data['salt'])
{
//Generateasaltforthisuserandassumethepasswordstoredindbisaplainmd5password
$this->login_data['salt']=generate_salt();
$this->login_data['password']=salt_password($this->login_data['password'],$this->login_data['salt']);
$sql_array=array(
"salt"=>$this->login_data['salt'],
"password"=>$this->login_data['password']
);
$db->update_query("users",$sql_array,"uid='{$this->login_data['uid']}'");
}
if(!$this->login_data['loginkey'])
{
$this->login_data['loginkey']=generate_loginkey();
$sql_array=array(
"loginkey"=>$this->login_data['loginkey']
);
$db->update_query("users",$sql_array,"uid='{$this->login_data['uid']}'");
}
}
$salted_password=md5(md5($this->login_data['salt']).$password);
$plugins->run_hooks('datahandler_login_verify_password_end',$args);
if($salted_password!==$this->login_data['password'])
Replace with:
PHP Code:
Code:
$plugins->run_hooks('datahandler_login_verify_password_end',$args);
if(validate_password_from_username($this->login_data['username'],$password)===false)