转自:https://learnku.com/articles/31169
可能每个 Laravel 开发者新建或者克隆一个 Laravel 程序的时候,composer install
之后最可能以及最重要的的第一步操作就是生成 APP_KEY
。
在这篇文章中我们会讨论 APP_KEY
能做的和不能做的,有些人会把用户密码的哈希处理与 APP_KEY
相关联(实际上它们毫无关联)。
什么是 APP_KEY
每一个 Laravel 程序都会生成一个随机的 32 位长度的字符串存储在.env
文件中的 APP_KEY
键值中,当我们新建 Laravel 项目的时候会自动为你创建一个,只有在克隆的时候你才有可能发现它没有被设定。
你可能看到过下面的错误,说明 APP_KEY
没有设定
你可以自己手动生成或者使用 php artisan key:generate
来进行创建 APP_KEY
。
当你的应用程序执行的时候,只有一个地方会用到 APP_KEY
:cookies。Laravel 使用它来加密所有的 cookies,在将 cookie 返回给用户之前 Laravel 会对 cookie 进行加密,然后再返回给用户,这样客户端就无法自己修改 cookie 来伪装成管理员或者其他用户了。
所以的加密和解密都在 Encrypter
中进行处理,其中主要使用了 [openssl_encrypt](https://secure.php.net/manual/en/function.openssl-encrypt.php)
进行加密。
有很多用户都会有一个误解,那就是 APP_KEY
是用来处理用户哈希密码的。事实上不是这样的。Laravel 的密码使用了 Hash::make()
或者 bcrypt()
来进行哈希处理,其中并没有用到 APP_KEY
。
加密 VS 哈希
在 Laravel 中有两个主要的加密 Facade,分别是 Crypt
(对称加密) 和 Hash
(单向加密哈希)。密码是哈希,而 cookie 则是对称加密。
对称加密
假设我想发送一条加密的信息给我的好友 A。我们商议好了一个用于加密和解密的 key:
$key = "dont-panic";
当我想要发送一条只有上面的 key 能解锁的信息时,我们可以使用 openssl_encrypt()
(Laravel 的 Crypt
也是使用的这个方法),具体如下:
$message = "So long and thanks for all the fish";
$key = "dont-panic";
$cipher = "AES-256-CBC";
echo openssl_encrypt($message, $cipher, $key);
// JJEK8L4G3BCfY0evXDRxUke2zqAzq6i7wL/Px4SjaEHXqt3x7hsj4+PhVQaH4ujX
此时,你就可以把这段加密的代码发送给 A,然后他可以进行解密了。
$secret = "JJEK8L4G3BCfY0evXDRxUke2zqAzq6i7wL/Px4SjaEHXqt3x7hsj4+PhVQaH4ujX";
$key = "dont-panic";
$cipher = "AES-256-CBC";
echo openssl_decrypt($secret, $cipher, $key);
// So long and thanks for all the fish
Laravel 的 cookie 加密解密也是同理,只不过 key 使用的是 APP_KEY
。
单向哈希
当我们使用密码的时候,我们应当从不使用对称加密的方法,来避免用户可能解密密码。这表示 Crypt
无法胜任,因此我们需要使用哈希方法,具有如下的特点:
- 快速:计算机能够快速的生成哈希值
- 确定性:针对同样的输入,输出是固定的
- 随机性:即使只更改一位字符串,哈希之后的输出应该十分不同
- 唯一性:碰撞概率应该非常非常的小
- 难于被暴力破解: 哈希之后的值应当难以被暴力破解
你应当听说过许多的单向哈希算法,例如 md5
和 SHA-1
。在 Laravel 中使用了 PHP 的原生方法 password_hash()
,它使用的哈希算法叫 bcrypt
。
use Illuminate\Support\Facades\Hash;
$password = "dont-panic";
echo Hash::make($password);
// $2y$10$hEEF0lv4spxnvw5O4XyLZ.QjCE1tCu8HjMpWhmCS89J0EcSW0XELu
如果你曾经查看过 users
数据表,那么上面的输出你可能会似曾相识。下面解释一下其中的含义:
$2y$
表示我们使用了blowfish
算法(bcrypt)10$
表示算法使用的 cost(值越高表示生成哈希的时间越长)hEEF0lv4spxnvw5O4XyLZ.
表示一个 22 位的随机 “盐”QjCE1tCu8HjMpWhmCS89J0EcSW0XELu
哈希结果
由于这是一个单向哈希,因此我们无法进行解密,我们能做的只是去验证其是否匹配。
use Illuminate\Support\Facades\Hash;
$input = request()->get('password'); // "dont-panic"
$hash = '$2y$10$hEEF0lv4spxnvw5O4XyLZ.QjCE1tCu8HjMpWhmCS89J0EcSW0XELu';
return Hash::check($input, $hash);
// true
因此我们可以看到,在对称加密中我们使用到了 APP_KEY
,而在密码哈希的时候我们是不需要使用它的。
总结
- 更改
APP_KEY
不会使用户的密码失效 - 更改
APP_KEY
会使 session 和 cookie 失效,导致当前已登录用户退出登录 - 不要害怕你的
APP_KEY
- 如果你在其他地方使用了 Laravel 的加密方法,那么你需要制定一个计划来应对
APP_KEY
的更改