跳轉至內容

雜湊

簡介

Laravel 的 Hash 門面(facade) 為儲存使用者密碼提供了安全的 Bcrypt 和 Argon2 雜湊演算法。如果您正在使用 Laravel 應用入門套件,預設情況下,註冊和身份驗證將使用 Bcrypt。

Bcrypt 是雜湊密碼的絕佳選擇,因為它的“工作因子(work factor)”是可調的,這意味著生成雜湊所需的時間可以隨著硬體效能的提升而增加。在處理密碼雜湊時,慢即是好。演算法執行雜湊所需的時間越長,惡意使用者生成可用於暴力破解攻擊的“彩虹表”(所有可能的字串雜湊值集合)所需的時間就越長。

配置

預設情況下,Laravel 在雜湊資料時使用 bcrypt 雜湊驅動。不過,它也支援其他幾種雜湊驅動,包括 argonargon2id

你可以透過 HASH_DRIVER 環境變數指定應用程式的雜湊驅動。但是,如果你想自定義 Laravel 雜湊驅動的所有選項,你應該使用 config:publish Artisan 命令釋出完整的 hashing 配置檔案。

1php artisan config:publish hashing

基本用法

雜湊密碼

你可以透過呼叫 Hash 門面的 make 方法來加密密碼:

1<?php
2 
3namespace App\Http\Controllers;
4 
5use Illuminate\Http\RedirectResponse;
6use Illuminate\Http\Request;
7use Illuminate\Support\Facades\Hash;
8 
9class PasswordController extends Controller
10{
11 /**
12 * Update the password for the user.
13 */
14 public function update(Request $request): RedirectResponse
15 {
16 // Validate the new password length...
17 
18 $request->user()->fill([
19 'password' => Hash::make($request->newPassword)
20 ])->save();
21 
22 return redirect('/profile');
23 }
24}

調整 Bcrypt 工作因子

如果你使用的是 Bcrypt 演算法,make 方法允許你透過 rounds 選項管理演算法的工作因子;不過,Laravel 預設管理的工作因子對大多數應用程式來說已經足夠了。

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

調整 Argon2 工作因子

如果你使用的是 Argon2 演算法,make 方法允許你透過 memorytimethreads 選項來管理演算法的工作因子;不過,Laravel 預設管理的值對大多數應用程式來說已經足夠了。

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

有關這些選項的更多資訊,請參閱 PHP 官方關於 Argon 雜湊的文件

驗證密碼與雜湊值是否匹配

Hash 門面提供的 check 方法允許你驗證給定的純文字字串是否與給定的雜湊值匹配。

1if (Hash::check('plain-text', $hashedPassword)) {
2 // The passwords match...
3}

判斷密碼是否需要重新雜湊

Hash 門面提供的 needsRehash 方法允許你判斷自密碼被雜湊以來,雜湊器所使用的工作因子是否發生了變化。一些應用程式會選擇在身份驗證過程中執行此檢查。

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

雜湊演算法驗證

為了防止雜湊演算法被篡改,Laravel 的 Hash::check 方法會首先驗證給定的雜湊值是否是使用應用程式當前選定的雜湊演算法生成的。如果演算法不一致,將丟擲 RuntimeException 異常。

對於大多數應用程式,這是預期行為,因為雜湊演算法通常不會變更,而演算法不同往往預示著惡意攻擊。然而,如果你的應用程式需要支援多種雜湊演算法(例如在從一種演算法遷移到另一種演算法時),你可以透過將 HASH_VERIFY 環境變數設定為 false 來停用雜湊演算法驗證。

1HASH_VERIFY=false