服务端必修课:加密解密和哈希

2,883 阅读3分钟

「这是我参与11月更文挑战的第20天,活动详情查看:2021最后一次更文挑战

加密解密、哈希算法 是服务端开发的必修课。

之前整理过一篇介绍对称加密和非对称加密,以及如何在项目中运用的文章,反响还不错。

有兴趣的同学可以查看参考https加解密思路 实现自己网络请求数据传输的安全性,一致性,防篡改。(对称加密+非对称加密)

今天整理一下Laravel的加密解密以及哈希算法相关的知识点。

加密解密

介绍

Laravel 的加密机制使用的是 OpenSSL 所提供的 AES-256 和 AES-128 加密。

建议使用 Laravel 内建的加密工具,而不是用其它的加密算法。

所有 Laravel 加密之后的结果都会使用消息认证码 (MAC) 签名,使其底层值不能在加密后再次修改。

配置

在使用 Laravel 的加密工具之前,我们必须先设置 config/app.php 配置文件中的 key 配置项。

该配置项由环境变量 APP_KEY 设定。

应当使用 php artisan key:generate 命令来生成该变量的值

原理:key:generate 命令将使用 PHP 的安全随机字节生成器为你的应用程序构建加密安全密钥。

基本用法

加密一个值

我们可以使用 Crypt 门面提供的 encryptString 来加密一个值。

所有加密的值都使用 OpenSSL 的 AES-256-CBC 来进行加密。

此外,所有加密过的值都会使用消息认证码 (MAC) 来签名,以检测加密字符串是否被篡改过:

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Crypt;

class DigitalOceanTokenController extends Controller
{
    /**
     * 为用户存储一个 DigitalOcean API 令牌
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function storeSecret(Request $request)
    {
        $request->user()->fill([
            'token' => Crypt::encryptString($request->token),
        ])->save();
    }
}

解密一个值

我们可以使用 Crypt 门面提供的 decryptString 来进行解密。

如果该值不能被正确解密,例如消息认证码 (MAC) 无效,会抛出异常

Illuminate\Contracts\Encryption\DecryptException:

use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Support\Facades\Crypt;

try {
    $decrypted = Crypt::decryptString($encryptedValue);
} catch (DecryptException $e) {
    //
}

哈希

介绍

Laravel Hash facade 为存储用户密码提供了安全的 Bcrypt 和 Argon2 哈希加密方式。

如果我们正在使用 Laravel 应用初始脚手架 ,默认情况下,将使用 Bcrypt 进行注册和身份验证。

Bcrypt 是加密密码的一个很好的选择,因为它的 “加密系数” 是可调的,这意味着生成散列所需的时间可以随着硬件功率的增加而增加。

注意:加密密码时速度慢是相对比较好的。

算法对密码进行哈希运算的时间越长,恶意用户生成所有可能用于对应用程序进行暴力攻击的字符串哈希值的 “彩虹表” 的时间就越长。

配置

我们可以在 config/hashing.php 配置文件中配置默认哈希驱动程序。

目前支持三种驱动程序: Bcrypt 和 Argon2 (Argon2i and Argon2id variants)。

注意:Argon2i 驱动程序需要 PHP 7.2.0 或更高版本,而 Argon2id 驱动程序则需要 PHP 7.3.0 或更高版本。

基本使用

哈希密码

我们可以通过调用 Hash facade 的 make 方法来加密你的密码:

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;

class PasswordController extends Controller
{
    /**
     * Update the password for the user.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request)
    {
        // Validate the new password length...

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

调整 Bcrypt 加密系数

如果使用 Bcrypt 算法,你可以在 make 方法中使用 rounds 选项来配置该算法的加密系数。然而,对大多数应用程序来说,默认值就足够了:

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

调整 Argon2 加密系数

如果使用 Argon2 算法,我们可以在 make 方法中使用 memory,time 和 threads 选项来配置该算法的加密系数。

对大多数应用程序来说,默认值就足够了:

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

密码散列 / 哈希验证

check 方法能为我们验证一段给定的未加密字符串与给定的散列 / 哈希值是否一致:

if (Hash::check('xxxx', $hashedPassword)) {
    // 密码匹配……
}

检查密码是否需要重新散列 / 哈希

needsRehash 方法可以为您检查当散列 / 哈希的加密系数改变时,您的密码是否被新的加密系数重新加密过。某些应用程序选择在身份验证时执行这一项检查:

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

总结

不管是政策要求还是技术要求,保证数据安全性,保护用户隐私都是行业趋势。

我们要把数据安全问题牢记于心,掌握加密解密知识,保证数据安全。

最后

欢迎大家关注我的微信公众号:程序员升级打怪之旅

同样欢迎关注我的专栏服务端从入门到精通,整理了深入浅出的服务端开发总结,包括:Go Java Php

如有问题可以加本人微信交流,微信号:wangzhongyang0601

👍🏻:觉得有收获请点个赞鼓励一下!

🌟:收藏文章,方便回看哦!

💬:评论交流,互相进步!