哈希

简介

Laravel 的 Hash 门面提供了安全的 Bcrypt 和 Argon2 哈希,用来存储用户密码。如果你在用 Laravel 应用起步套件,注册和认证默认就会用 Bcrypt。

Bcrypt 很适合哈希密码,因为它的「工作因子(work factor)」是可调的——也就是说,随着硬件性能提升,你可以延长生成一个哈希所需的时间。哈希密码时,慢就是好。算法哈希一个密码耗时越长,恶意用户构造用于爆破攻击的「彩虹表」(把所有可能的字符串预先哈希好的对照表)所需的时间就越久。

配置

Laravel 默认使用 bcrypt 哈希驱动来哈希数据。不过还支持其他几种哈希驱动,包括 argon 和 argon2id。

你可以通过 HASH_DRIVER 环境变量指定应用的哈希驱动。但如果想自定义 Laravel 所有的哈希驱动选项,你应该用 config:publish Artisan 命令发布完整的 hashing 配置文件:

php artisan config:publish hashing

基本用法

哈希密码

你可以调用 Hash 门面上的 make() 方法来哈希一个密码:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;

class PasswordController extends Controller
{
    /**
     * Update the password for the user.
     */
    public function update(Request $request): RedirectResponse
    {
        // Validate the new password length...

        $request->user()->fill([
            'password' => Hash::make($request->newPassword)
        ])->save();

        return redirect('/profile');
    }
}

调整 Bcrypt 工作因子

如果你用的是 Bcrypt 算法,make() 方法允许你通过 rounds 选项来调整算法的工作因子;不过 Laravel 管理的默认工作因子对大多数应用来说已经够用了:

$hashed = Hash::make('password', [
    'rounds' => 12,
]);

调整 Argon2 工作因子

如果你用的是 Argon2 算法,make() 方法允许你通过 memory、time 和 threads 选项来调整算法的工作因子;不过 Laravel 管理的默认值对大多数应用来说已经够用了:

$hashed = Hash::make('password', [
    'memory' => 1024,
    'time' => 2,
    'threads' => 2,
]);

信息

关于这些选项的更多信息,请参考 PHP 官方 Argon 哈希文档。

验证密码与哈希是否匹配

Hash 门面提供的 check() 方法可以验证给定的明文字符串是否与给定的哈希匹配:

if (Hash::check('plain-text', $hashedPassword)) {
    // 密码匹配...
}

判断密码是否需要重新哈希

Hash 门面提供的 needsRehash() 方法可以判断哈希器使用的工作因子在密码被哈希之后是否已经改变。有些应用会选择在应用的认证过程中执行这项检查:

if (Hash::needsRehash($hashed)) {
    $hashed = Hash::make('plain-text');
}

哈希算法校验

为了防止哈希算法被人做手脚,Laravel 的 Hash::check() 方法会先验证给定的哈希是否是用应用当前选定的哈希算法生成的。如果算法不一致,会抛出 RuntimeException 异常。

这对大多数应用来说是符合预期的行为——哈希算法通常不会变,出现不同的算法可能就是恶意攻击的信号。不过,如果你需要在应用中同时支持多种哈希算法(比如从一种算法迁移到另一种),可以把 HASH_VERIFY 环境变量设为 false 来禁用哈希算法校验:

HASH_VERIFY=false