involix / elocryptfive
Requires
- php: >=5.6.0
- illuminate/config: ^5.0
- illuminate/console: ^5.0
- illuminate/container: ^5.0
- illuminate/contracts: ^5.0
- illuminate/encryption: ^5.0
- illuminate/support: ^5.0
- paragonie/random_compat: ^1.1|^2.0
Requires (Dev)
- phpunit/phpunit: ~4.0
README
自动加密和解密 Laravel 5 Eloquent 值。
首先阅读此内容
加密值通常比纯文本值长。有时可能会长很多。您可能需要将数据库表中的列宽度扩展,以便存储加密值。
如果您正在加密长字符串,如 JSON 块,则加密值可能比 VARCHAR 字段支持的长度要长,您可能需要将列类型扩展到 TEXT 或 LONGTEXT。
此功能做什么?
通过在模型属性中存储数据时加密数据,并在从模型属性中检索数据时解密数据,透明地对 Laravel 应用程序中数据库表存储的列进行加密和解密。
所有加密的数据都以前缀标签(默认 __ELOCRYPT__:)开头,以便可以轻松识别加密数据。
这支持存储加密或非加密数据的列,以便更容易迁移。可以正确地从列中读取数据,无论其是否加密,但将其保存回列时将自动加密。
要求和推荐
- Laravel 5.1 LTS(未在 5.2 及更高版本上进行测试)
- PHP > 5.6.0(需要 PHP 5.6 中添加的
hash_equals()函数) - PHP openssl 扩展。
- 您的操作系统上有一个正常工作的 OpenSSL 实现。大多数 Linux 发行版和其他形式的 Unix(如 *BSD)都预装了 OpenSSL。Windows 系统上是否有正常工作的 OpenSSL 实现取决于您的 LA?P 栈是如何构建的。我无法为没有 OpenSSL 库的系统提供安装或使用 ElocryptFive 的支持。
贡献者
这是 Darren Taylor 的 Laravel 4 "elocrypt" 包,已移植到 Laravel 5。我进行了以下添加/更改
-
在单独的函数中执行加密(encryptedAttribute 和 decryptedAttribute 而不是在 __set 和 __get 内部,并从 setAttribute 和 getAttribute 调用这些函数,因为这对于具有新 casts 功能的 Laravel 5 更合适。例如,您可以将字段添加到
$casts和$encrypts中,这样数组可以先被转换为 JSON 字符串,然后加密。它也应该适用于 Lumen。 -
将所有加密值前缀为标签字符串(默认
__ELOCRYPT__:),以便可以检测和正确处理纯文本数据。将现有数据库中的所有纯文本数据更新为加密数据的脚本编写任务留给读者。
原始 Laravel 4 包在此处: https://github.com/dtisgodsson/elocrypt
感谢 Brandon Surowiec 对内部方法进行了大量重构。
安装
您可以通过将以下内容添加到您的 composer.json 文件来使用 Composer 安装此包
"require": {
"delatbabel/elocryptfive": "~1.0"
}
然后,您必须运行以下命令
composer update
一旦 composer update 完成后,请将服务提供者添加到应用程序的 config/app.php 文件中的 providers 数组中。
'providers' => [ ... Involix\Elocrypt\ElocryptServiceProvider::class, ],
配置
使用以下命令发布配置文件:
php artisan vendor:publish --provider='Involix\Elocrypt\ElocryptServiceProvider'
然后您可以更改 .env 配置文件中的默认前缀标记字符串
ELOCRYPT_PREFIX=__This_is_encrypted_data__
或者,您还可以直接在 config/elocrypt.php 文件中更改默认设置
return [ 'prefix' => env('ELOCRYPT_PREFIX', '__This_is_encrypted_data__') ]
使用方法
简单地将 Elocrypt 特性引用到您希望应用加密的任何 Eloquent 模型中,并定义一个包含要加密的属性列表的 $encrypts 数组。
例如
use Delatbabel\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 Delatbabel\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 v 5.1.12 中 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 -- 已在此扩展以解密数据。
密钥和 IV
使用的密钥和加密算法与 Laravel Encrypter 服务相同,并在 config/app.php 中定义如下
'key' => env('APP_KEY', 'SomeRandomString'), 'cipher' => 'AES-256-CBC',
我建议生成一个 32 个字符的随机字符串作为加密密钥,并使用 AES-256-CBC 作为加密数据的密文。如果您正在加密长数据字符串,则 AES-256-CBC-HMAC-SHA1 会更好。
加密的 IV 是随机生成的。
常见问题解答 (FAQ)
手动加密数据
您可以使用 encryptedAttribute() 和 decryptedAttribute() 函数手动加密或解密数据。以下是一个示例:
$user = new User(); $encryptedEmail = $user->encryptedAttribute(Input::get("email"));
加密和解密与搜索
由于数据已被加密,您将无法在加密数据上进行搜索。比较加密值需要固定 IV,这会引入安全风险。
如果您需要搜索数据,则可以选择以下方法:
- 不加密,或
- 对数据进行哈希处理,然后搜索哈希值而不是加密值。使用 SHA256 等知名哈希算法。
您可以将哈希值和加密值都存储起来,使用哈希值进行搜索,并检索加密值以供其他用途。
加密和认证
与搜索相同,认证也面临同样的问题,因为认证需要用户搜索。
如果您有一个认证表,其中加密了用户数据,包括登录数据(例如电子邮件),这将阻止 Auth::attempt 函数工作。例如,以下代码将无法正常工作:
$auth = Auth::attempt(array( "email" => Input::get("email"), "password" => Input::get("password"), ), $remember);
至于搜索,比较加密的电子邮件将不起作用,因为这需要一个固定的 IV,这会引入安全问题。
您需要做的是使用众所周知的散列函数(例如 SHA256 或 RIPE-MD160)对电子邮件地址进行散列,而不是加密它,然后在 Auth::attempt 函数中比较散列值。
如果您需要访问电子邮件地址,则可以存储散列和加密的电子邮件地址,使用散列值进行认证,并检索加密值用于其他用途(例如发送电子邮件)。