From 7d9535007eadb03eac5dac21b7426a3832baa3bd Mon Sep 17 00:00:00 2001 From: printempw Date: Sun, 8 Jan 2017 12:49:32 +0800 Subject: [PATCH] support hashing passwords with password_hash() --- .env.example | 5 +++-- app/Http/Controllers/AuthController.php | 2 +- app/Http/Controllers/UserController.php | 6 +++--- app/Models/User.php | 22 ++++++++++++---------- app/Providers/AppServiceProvider.php | 10 +++++++++- app/Services/Cipher/BaseCipher.php | 23 +++++++++++++++++++++++ app/Services/Cipher/EncryptInterface.php | 13 +++++++++++-- app/Services/Cipher/MD5.php | 4 ++-- app/Services/Cipher/PHP_PASSWORD_HASH.php | 19 +++++++++++++++++++ app/Services/Cipher/SALTED2MD5.php | 4 ++-- app/Services/Cipher/SALTED2SHA256.php | 4 ++-- app/Services/Cipher/SALTED2SHA512.php | 8 ++++---- app/Services/Cipher/SHA256.php | 4 ++-- app/Services/Cipher/SHA512.php | 4 ++-- 14 files changed, 95 insertions(+), 33 deletions(-) create mode 100644 app/Services/Cipher/BaseCipher.php create mode 100644 app/Services/Cipher/PHP_PASSWORD_HASH.php diff --git a/.env.example b/.env.example index 97db46b5..0fb120f8 100644 --- a/.env.example +++ b/.env.example @@ -30,9 +30,10 @@ DB_PREFIX = null # Encrypt Method for Passwords. # -# Available values: MD5, SALTED2MD5, (SALTED2)SHA256, (SALTED2)SHA512 +# Available values: PHP_PASSWORD_HASH, (SALTED2)MD5, (SALTED2)SHA256, (SALTED2)SHA512 +# New sites are highly recommend to use PHP_PASSWORD_HASH. # -PWD_METHOD = SALTED2MD5 +PWD_METHOD = PHP_PASSWORD_HASH # Salt # Change it to any random string to secure your passwords & tokens. diff --git a/app/Http/Controllers/AuthController.php b/app/Http/Controllers/AuthController.php index c45c0276..cc773b0e 100644 --- a/app/Http/Controllers/AuthController.php +++ b/app/Http/Controllers/AuthController.php @@ -49,7 +49,7 @@ class AuthController extends Controller if (!$user) { return json(trans('auth.validation.user'), 2); } else { - if ($user->checkPasswd($request->input('password'))) { + if ($user->verifyPassword($request->input('password'))) { Session::forget('login_fails'); Session::put('uid' , $user->uid); diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index 5823cd0e..5355fcd0 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -79,7 +79,7 @@ class UserController extends Controller 'new_password' => 'required|min:8|max:16' ]); - if (!$this->user->checkPasswd($request->input('current_password'))) + if (!$this->user->verifyPassword($request->input('current_password'))) return json(trans('user.profile.password.wrong-password'), 1); if ($this->user->changePasswd($request->input('new_password'))) @@ -93,7 +93,7 @@ class UserController extends Controller 'password' => 'required|min:8|max:16' ]); - if (!$this->user->checkPasswd($request->input('password'))) + if (!$this->user->verifyPassword($request->input('password'))) return json(trans('user.profile.email.wrong-password'), 1); if ($this->user->setEmail($request->input('new_email'))) @@ -106,7 +106,7 @@ class UserController extends Controller 'password' => 'required|min:8|max:16' ]); - if (!$this->user->checkPasswd($request->input('password'))) + if (!$this->user->verifyPassword($request->input('password'))) return json(trans('user.profile.delete.wrong-password'), 1); if ($this->user->delete()) { diff --git a/app/Models/User.php b/app/Models/User.php index caf6d9f8..b6c232bf 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -69,26 +69,28 @@ class User extends Model * @param string $rawPasswd * @return bool */ - public function checkPasswd($rawPasswd) + public function verifyPassword($rawPasswd) { - return (static::encryptPassword($rawPasswd, $this) == $this->password); + // compare directly if any responses is returned by event dispatcher + if ($result = static::getEncryptedPwdFromEvent($rawPasswd, $this)) { + return ($result == $this->password); + } + + return app('cipher')->verify($rawPasswd, $this->password, config('secure.salt')); } /** - * Encrypt user's password. + * Try to get encrypted password from event dispatcher. * * @param string $rawPasswd * @param User $user * @return mixed */ - protected static function encryptPassword($rawPasswd, User $user) + protected static function getEncryptedPwdFromEvent($rawPasswd, User $user) { $responses = event(new EncryptUserPassword($rawPasswd, $user)); - return Arr::get($responses, 0, - // encrypt with current cipher if no response is returned by the event dispatcher - app('cipher')->encrypt($rawPasswd, config('secure.salt')) - ); + return Arr::get($responses, 0); } /** @@ -112,7 +114,7 @@ class User extends Model $user->save(); // save again with password - $user->password = static::encryptPassword($password, $user); + $user->password = static::getEncryptedPwdFromEvent($password, $user) ?: app('cipher')->hash($password, config('secure.salt')); $user->save(); return $user; @@ -131,7 +133,7 @@ class User extends Model if (isset($responses[0])) { $this->password = $responses[0]; } else { - $this->password = app('cipher')->encrypt($new_passwd, config('secure.salt')); + $this->password = app('cipher')->hash($new_passwd, config('secure.salt')); } return $this->save(); diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 0f53dc0e..a5921e71 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -8,6 +8,7 @@ use Validator; use App\Events; use Illuminate\Support\Arr; use Illuminate\Support\ServiceProvider; +use App\Exceptions\PrettyPageException; class AppServiceProvider extends ServiceProvider { @@ -49,7 +50,14 @@ class AppServiceProvider extends ServiceProvider public function register() { // register default cipher - $this->app->singleton('cipher', "App\Services\Cipher\\".config('secure.cipher')); + $className = "App\Services\Cipher\\".config('secure.cipher'); + + if (class_exists($className)) { + $this->app->singleton('cipher', $className); + } else { + exit(sprintf("No such encrypt method: [%s], please check your .env configuration.", config('secure.cipher'))); + } + $this->app->singleton('users', \App\Services\Repositories\UserRepository::class); $this->app->singleton('parsedown', \Parsedown::class); } diff --git a/app/Services/Cipher/BaseCipher.php b/app/Services/Cipher/BaseCipher.php new file mode 100644 index 00000000..4961cd43 --- /dev/null +++ b/app/Services/Cipher/BaseCipher.php @@ -0,0 +1,23 @@ +hash($password, $salt) === $hash); + } + +} diff --git a/app/Services/Cipher/EncryptInterface.php b/app/Services/Cipher/EncryptInterface.php index b8a7a2c0..0da25468 100644 --- a/app/Services/Cipher/EncryptInterface.php +++ b/app/Services/Cipher/EncryptInterface.php @@ -5,11 +5,20 @@ namespace App\Services\Cipher; interface EncryptInterface { /** - * Encrypt given string w/ or w/o salt + * Encrypt given string with given salt. * * @param string $value * @param string $salt * @return string */ - public function encrypt($value, $salt = ""); + public function hash($value, $salt = ""); + + /** + * Verifies that the given hash matches the given password. + * + * @param string $password + * @param string $hash + * @return bool + */ + public function verify($password, $hash); } diff --git a/app/Services/Cipher/MD5.php b/app/Services/Cipher/MD5.php index 9a7e5a27..46897b02 100644 --- a/app/Services/Cipher/MD5.php +++ b/app/Services/Cipher/MD5.php @@ -2,12 +2,12 @@ namespace App\Services\Cipher; -class MD5 implements EncryptInterface +class MD5 extends BaseCipher { /** * Once MD5 hash */ - public function encrypt($value, $salt = "") + public function hash($value, $salt = "") { return md5($value); } diff --git a/app/Services/Cipher/PHP_PASSWORD_HASH.php b/app/Services/Cipher/PHP_PASSWORD_HASH.php new file mode 100644 index 00000000..03613e48 --- /dev/null +++ b/app/Services/Cipher/PHP_PASSWORD_HASH.php @@ -0,0 +1,19 @@ +