involix / elocrypt
轻松在Laravel 5/6/7/8中加密/解密Eloquent属性
Requires
- php: >=7.0.0
- illuminate/config: ^5.0|^6.0|^7.0|^8.0
- illuminate/console: ^5.0|^6.0|^7.0|^8.0
- illuminate/container: ^5.0|^6.0|^7.0|^8.0
- illuminate/contracts: ^5.0|^6.0|^7.0|^8.0
- illuminate/encryption: ^5.0|^6.0|^7.0|^8.0
- illuminate/support: ^5.0|^6.0|^7.0|^8.0
- paragonie/random_compat: ^9.99.99
Requires (Dev)
- phpunit/phpunit: ^5.0|^6.0|^7.0|^8.0|^9.0
README
自动加密和解密Laravel Eloquent值。
请先阅读此内容
加密值通常比纯文本值长。有时长得多。您可能会发现数据库表中列的宽度需要扩展以存储加密值。
如果您正在加密长字符串,如JSON blob,则加密值可能比VARCHAR字段支持的还要长,并且您可能需要将列类型扩展到TEXT或LONGTEXT。
它做什么?
通过在模型属性中存储数据时加密以及从模型属性中检索数据时解密,透明地加密数据库表中的列。
所有加密的数据都以前缀标签(默认为__ELOCRYPT__:
)开头,以便轻松识别加密数据。
这支持存储加密或非加密数据的列,以便简化迁移。无论数据是否加密,都可以正确地从列中读取,但在将数据保存回这些列时将自动加密。
要求和推荐
- Laravel 5+
- PHP > 7
- PHP openssl扩展。
- 操作系统上工作的OpenSSL实现。OpenSSL与大多数Linux发行版和其他Unix形式(如*BSD)预构建。Windows系统上可能或可能没有可工作的OpenSSL实现,这取决于您的LA?P堆栈是如何构建的。对于没有OpenSSL库的系统,我无法提供安装或使用ElocryptFive的支持。
贡献者
这是Darren Taylor的Laravel 4 "elocrypt"包,由Eugene Cooper移植到Laravel 6/7/8。
感谢Brandon Surowiec对内部方法的广泛重构。
安装
您可以通过将以下内容添加到您的composer.json
文件来通过Composer安装此包
"require": {
"involix/elocrypt": "^1.8"
}
然后,运行以下命令
composer update
一旦composer update
完成,请将服务提供程序添加到您的应用程序的config/app.php
文件中的providers
数组中
'providers' => [ ... Involix\Elocrypt\ElocryptServiceProvider::class, ],
配置
使用以下命令发布配置文件
php artisan vendor:publish --provider='Involix\Elocrypt\ElocryptServiceProvider'
然后,您可以在.env
配置文件中更改默认的前缀标签字符串
ELOCRYPT_PREFIX=__encrypted__
或者您可以直接在config/elocrypt.php
文件中更改默认值
return [ 'prefix' => env('ELOCRYPT_PREFIX', '__encrypted__') ]
用法
只需在任何您希望应用加密的Eloquent模型中引用Elocrypt特质,并定义一个包含要加密的属性列表的$encrypts
数组。
例如
use Involix\Elocrypt\Elocrypt; class User extends Eloquent { use Elocrypt; /** * The attributes that should be encrypted on save. * * @var array */ protected $encrypts = [ 'address_line_1', 'first_name', 'last_name', 'postcode' ]; }
您可以将$casts
和$encrypts
结合使用以存储加密数组。数组首先被转换为JSON,然后被加密。
例如
use Involix\Elocrypt\Elocrypt; class User extends Eloquent { use Elocrypt; protected $casts = ['extended_data' => 'array']; protected $encrypts = ['extended_data']; }
它是如何工作的?
通过包含Elocrypt特质,覆盖了Eloquent提供的setAttribute()和getAttributeFromArray()方法以包含一个额外的步骤。这个额外的步骤只是检查正在设置或获取的属性是否包含在模型的$encrypts
数组中,并相应地加密/解密它。
Illuminate\Database\Eloquent\Model中的方法摘要
该文档调查了Laravel模型类中截至Laravel的主要方法,并检查这些模型如何设置属性以及它们如何受此特质的影响。
- 构造函数 -- 调用fill()
- fill() -- 调用 setAttribute(),该函数已被扩展以加密数据。
- hydrate() -- 待定
- create() -- 调用构造函数,因此调用 fill()
- firstOrCreate -- 调用构造函数
- firstOrNew -- 调用构造函数
- updateOrCreate -- 调用 fill()
- update() -- 调用 fill()
- toArray() -- 调用 attributesToArray()
- jsonSerialize() -- 调用 toArray()
- toJson() -- 调用 toArray()
- attributesToArray() -- 调用 getArrayableAttributes()。
- getAttribute -- 调用 getAttributeValue()
- getAttributeValue -- 调用 getAttributeFromArray()
- getAttributeFromArray -- 调用 getArrayableAttributes()
- getArrayableAttributes -- 已在此处扩展以解密数据。
- setAttribute -- 已在此处扩展以加密数据。
- getAttributes -- 已在此处扩展以解密数据。
密钥和初始化向量
使用的密钥和加密算法符合 Laravel Encrypter 服务,并在 config/app.php
中定义如下
'key' => env('APP_KEY', 'SomeRandomString'), 'cipher' => 'AES-256-CBC',
我建议生成一个随机的 32 个字符的字符串作为加密密钥,并使用 AES-256-CBC 作为加密数据的加密方式。如果您正在加密长的数据字符串,则 AES-256-CBC-HMAC-SHA1 会更好。
加密的初始化向量是随机生成的。
常见问题解答
手动加密数据
您可以使用 encryptedAttribute()
和 decryptedAttribute()
函数手动加密或解密数据。以下是一个示例:
$user = new User(); $encryptedEmail = $user->encryptedAttribute(Input::get("email"));
加密和搜索
由于数据已被加密,因此您无法在加密数据上执行搜索。比较加密值将需要固定的初始化向量,这会引入安全问题。
如果您需要对数据进行搜索,则可以
- 不进行加密,或者
- 对数据进行哈希处理,并在哈希值上而不是加密值上进行搜索。使用如 SHA256 之类的知名哈希算法。
您可以同时存储哈希值和加密值,使用哈希值进行搜索,并检索加密值用于其他用途。
加密和身份验证
由于身份验证需要用户搜索,因此搜索的问题也适用于身份验证。
如果您有一个包含加密用户数据的身份验证表(例如,包括登录数据(例如电子邮件)),这将阻止 Auth::attempt 的工作。例如,以下代码将不起作用:
$auth = Auth::attempt(array( "email" => Input::get("email"), "password" => Input::get("password"), ), $remember);
对于搜索,比较加密的电子邮件地址将不起作用,因为它需要固定的初始化向量,这会引入安全问题。
您需要做的是使用知名的哈希函数(例如 SHA256 或 RIPE-MD160)对电子邮件地址进行哈希处理,而不是加密它,然后在 Auth::attempt 函数中比较哈希值。
如果您需要访问电子邮件地址,则可以同时存储哈希值和加密的电子邮件地址,使用哈希值进行身份验证,并检索加密值用于其他用途(例如发送电子邮件)。