如何处理laravel中的加密数据列

问题描述

我正在使用 AWS KMS 为每个用户的会话生成唯一的密钥对,然后加密定义为使用开放 ssl 加密的每个列。因此,我实现了以下特征,在保存/检索时加密和解密 getEncryptAttributes 中定义的字段:

trait HasEncryption
{
    /**
     * Set the array of encrypted attributes which will be stored in the database as encrypted text. Ensure the database
     * column type to be binary. If you know a precise size,set it like in the respective database migration linked below. Else,use laravel's builtin $table->binary()
     * @return string[]
     * @see \AddCipherKeyToUsers::up()
     */
    abstract public function getEncryptAttributes(): array;

    /**
     * Init the model event-handlers
     *
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public static function bootHasEncryption()
    {
        // On save: Encrypt the data and store the keys to decrypt in the database
        static::saving(function (Model $model) {
            // For all encrypt-attributes,encrypt the data
            foreach ($model->getEncryptAttributes() as $attribute) {
                if (!is_null($model->getAttribute($attribute))) {
                    $res = $model->encryptionService->encrypt($model->getAttribute($attribute));
                    $model->setAttribute($attribute,$res['encrypted']);
                }
            }
            // If something was encrypted,store the encryption keys to the database to use for decryption
            if (isset($res)) {
                $model->setAttribute('encrypted_key',$res['key']);
                $model->setAttribute('encryption_iv',$res['iv']);
            }
            return $model;
        });

        // On retreive: Decrypt all attributes using the keys stored above
        static::retrieved(function (Model $model) {
            // For all encrypt-attributes,decrypt the data with the encryption keys stored on encrypt method
            foreach ($model->getEncryptAttributes() as $attribute) {
                if (!is_null($model->getAttribute($attribute)) && !is_null($model->getAttribute('encrypted_key')) && !is_null($model->getAttribute('encryption_iv'))) {
                    $decrypted = $model->encryptionService->decrypt($model->getAttribute($attribute),$model->getAttribute('encrypted_key'),$model->getAttribute('encryption_iv'));
                    $model->setAttribute($attribute,$decrypted);
                }
            }
            return $model;
        });
    }

    /**
     * Get the app's encryption service singelton through magic attribute accessor
     *
     * @return EncryptionService
     */
    public function getEncryptionServiceAttribute(): EncryptionService
    {
        return app()->make(EncryptionService::class);
    }
}

EncryptionService 是一个单例,它将在会话的生命周期内使用相同的键。如果会话中没有可用的密钥,它将连接到 AWS STS 并为此会话获取新令牌。

我们不能对 aurora 数据库使用默认的 AWS 加密,因为数据必须以加密状态通过网络,而且每个用户的数据都必须独立加密。

现在在实践中,加密和解密在存储某些东西时起作用,然后重新加载和读取数据。但是当我有这样的事情时:

$thing->setAttribute('encrypted_attribute','value');
$thing->save();
dump($thing->getAttribute('encrypted_attribute'); // will print ú©N╬B═Ø©ªx\rÒ┤Ò·&

saving 观察者显然会修改加密属性,但我只想加密实际进入数据库的内容,但保留本地状态。否则,例如多次保存时,它也会再次加密二进制数据,而不是使用实际属性。

有没有办法按照我的方向实现这一点,或者您是否建议采用完全不同的设计来实现部分加密的数据库?


编辑:有时,提出问题有助于我的大脑。我认为 eloquent 模型具有触发 finishSave 事件的 saved 方法。所以我在特征中添加了 static::saved 并在那里解密。似乎工作。不过,您是否发现此设计存在任何潜在缺陷,或者您是否体验过通常如何实现?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...