草庐IT

php - CakePHP 3中表单字段的加密/解密

coder 2024-04-24 原文

我想在添加/编辑某些表单字段时对其进行加密,并在蛋糕查找它们时对其进行解密。 这是在 v2.7.2 中对我有用的代码:

core.php

Configure::write('Security.key','secretkey');

app/model/patient.php.

public $encryptedFields = array('patient_surname', 'patient_first_name');

public function beforeSave($options = array()) {
    foreach($this->encryptedFields as $fieldName){
        if(!empty($this->data[$this->alias][$fieldName])){
            $this->data[$this->alias][$fieldName] = Security::encrypt(
                $this->data[$this->alias][$fieldName],
                Configure::read('Security.key')
            );
        }
    }
    return true;
}

public function afterFind($results, $primary = false) {

    foreach ($results as $key => $val) {
        foreach($this->encryptedFields as $fieldName) {
            if (@is_array($results[$key][$this->alias])) {
                $results[$key][$this->alias][$fieldName] = Security::decrypt(
                    $results[$key][$this->alias][$fieldName],
                    Configure::read('Security.key')
                );
            }
        }
    }
    return $results;
}

据我所知,我必须将 $this->data[] 替换为模型生成的实体,并将 afterFind 方法替换为虚拟字段,但我无法将它们放在一起。

最佳答案

解决这个问题的方法不止一种(请注意以下代码是未经测试的示例代码!在使用这些代码之前,您应该先掌握新的基础知识)。

自定义数据库类型

一种是自定义数据库类型,它会在将值绑定(bind)到数据库语句时加密,并在获取结果时解密。这是我更喜欢的选项。

这是一个简单的例子,假设数据库列可以保存二进制数据。

src/Database/Type/CryptedType.php

这应该是 self 解释的,在转换为数据库时加密,在转换为 PHP 时解密。

<?php
namespace App\Database\Type;

use Cake\Database\Driver;
use Cake\Database\Type;
use Cake\Utility\Security;

class CryptedType extends Type
{
    public function toDatabase($value, Driver $driver)
    {
        return Security::encrypt($value, Security::getSalt());
    }

    public function toPHP($value, Driver $driver)
    {
        if ($value === null) {
            return null;
        }
        return Security::decrypt($value, Security::getSalt());
    }
}

src/config/bootstrap.php

注册自定义类型。

use Cake\Database\Type;
Type::map('crypted', 'App\Database\Type\CryptedType');

src/Model/Table/PatientsTable.php

最后将可加密的列映射到已注册的类型,就是这样,从现在开始一切都将自动处理。

// ...

use Cake\Database\Schema\Table as Schema;

class PatientsTable extends Table
{
    // ...
    
    protected function _initializeSchema(Schema $table)
    {
        $table->setColumnType('patient_surname', 'crypted');
        $table->setColumnType('patient_first_name', 'crypted');
        return $table;
    }

    // ...
}

参见 Cookbook > Database Access & ORM > Database Basics > Adding Custom Types

beforeSave 和结果格式化程序

一种不那么枯燥和更紧密耦合的方法,基本上是您的 2.x 代码的一个端口,将使用 beforeSave 回调/事件和结果格式化程序。例如,结果格式化程序可以附加在 beforeFind 事件/回调中。

beforeSave中,只需设置/获取传递的实体实例的值,您可以利用Entity::has()Entity::get ()Entity::set(),甚至可以使用数组访问,因为实体实现了 ArrayAccess

结果格式化程序基本上是一个 after find Hook ,您可以使用它轻松地迭代结果并修改它们。

这是一个基本的例子,不需要太多进一步的解释:

// ...

use Cake\Event\Event;
use Cake\ORM\Query;

class PatientsTable extends Table
{
    // ...
    
    public $encryptedFields = [
        'patient_surname',
        'patient_first_name'
    ];
    
    public function beforeSave(Event $event, Entity $entity, \ArrayObject $options)
    {
        foreach($this->encryptedFields as $fieldName) {
            if($entity->has($fieldName)) {
                $entity->set(
                    $fieldName,
                    Security::encrypt($entity->get($fieldName), Security::getSalt())
                );
            }
        }
        return true;
    }
    
    public function beforeFind(Event $event, Query $query, \ArrayObject $options, boolean $primary)
    {
        $query->formatResults(
            function ($results) {
                /* @var $results \Cake\Datasource\ResultSetInterface|\Cake\Collection\CollectionInterface */
                return $results->map(function ($row) {
                    /* @var $row array|\Cake\DataSource\EntityInterface */
                    
                    foreach($this->encryptedFields as $fieldName) {
                        if(isset($row[$fieldName])) {
                            $row[$fieldName] = Security::decrypt($row[$fieldName], Security::getSalt());
                        }
                    }
                    
                    return $row;
                });
            }
        );  
    }

    // ...
}

为了稍微解耦它,您还可以将其移动到一个行为中,以便您可以轻松地在多个模型之间共享它。

另见

关于php - CakePHP 3中表单字段的加密/解密,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32260229/

有关php - CakePHP 3中表单字段的加密/解密的更多相关文章

  1. 区块链之加解密算法&数字证书 - 2

    目录一.加解密算法数字签名对称加密DES(DataEncryptionStandard)3DES(TripleDES)AES(AdvancedEncryptionStandard)RSA加密法DSA(DigitalSignatureAlgorithm)ECC(EllipticCurvesCryptography)非对称加密签名与加密过程非对称加密的应用对称加密与非对称加密的结合二.数字证书图解一.加解密算法加密简单而言就是通过一种算法将明文信息转换成密文信息,信息的的接收方能够通过密钥对密文信息进行解密获得明文信息的过程。根据加解密的密钥是否相同,算法可以分为对称加密、非对称加密、对称加密和非

  2. ruby - Ruby 中的单 block AES 解密 - 2

    我需要尝试一些AES片段。我有一些密文c和一个keyk。密文已使用AES-CBC加密,并在前面加上IV。不存在填充,纯文本的长度是16的倍数。所以我这样做:aes=OpenSSL::Cipher::Cipher.new("AES-128-CCB")aes.decryptaes.key=kaes.iv=c[0..15]aes.update(c[16..63])+aes.final它工作得很好。现在我需要手动执行CBC模式,所以我需要单个block的“普通”AES解密。我正在尝试这个:aes=OpenSSL::Cipher::Cipher.new("AES-128-ECB")aes.dec

  3. ruby - 使用 AES 的 Rails 加密,过于复杂 - 2

    我在加密来self正在使用的第三方供应商的值时遇到问题。他们的指令如下:1)Converttheencryptionpasswordtoabytearray.2)Convertthevaluetobeencryptedtoabytearray.3)Theentirelengthofthearrayisinsertedasthefirstfourbytesontothefrontofthefirstblockoftheresultantbytearraybeforeencryption.4)EncryptthevalueusingAESwith:1.256-bitkeysize,2.25

  4. ruby - 你会如何在 Ruby 中表达成语 "with this object, if it exists, do this"? - 2

    在Ruby(尤其是Rails)中,您经常需要检查某物是否存在,然后对其执行操作,例如:if@objects.any?puts"Wehavetheseobjects:"@objects.each{|o|puts"hello:#{o}"end这是最短的,一切都很好,但是如果你有@objects.some_association.something.hit_database.process而不是@objects呢?我将不得不在if表达式中重复两次,如果我不知道实现细节并且方法调用很昂贵怎么办?显而易见的选择是创建一个变量,然后测试它,然后处理它,但是你必须想出一个变量名(呃),它也会在内存中

  5. ruby - 如何使用私钥加密完全加密 Ruby 中的数据? - 2

    首先,关于我们系统的一些信息,它基本上是建筑行业的电子招标解决方案。所以:列表项我们的系统有多家公司每个公司都有多个用户每家公司可以创建多个拍卖然后其他公司可以为可用的拍卖提交他们的出价。一个出价包含数百或数千个单独的项目,我们只需要加密这些记录的“价格”部分。我们面临的问题是,我们的大客户不希望我们知道投标价格,至少在投标过程中是这样,这是完全可以理解的。现在,我们只是通过对称加密对价格进行加密,因此即使价格在数据库中有效加密,他们担心的是我们拥有解密价格的key。因此,我们正在研究某种形式的公钥加密系统。以下是我们对解决方案的初步想法:当一家公司注册时,我们会使用OpenSSL为其

  6. ruby-on-rails - 我如何比较 'Bcrypt' Gem解密的密码和加密的密码 - 2

    我正在尝试对某些帖子的评论使用简单的身份验证。用户使用即时ID和密码输入评论我使用“bcrypt”gem将密码存储在数据库中。在comments_controller.rb中像这样@comment=Comment.new(comment_params)bcrypted_pwd=BCrypt::Password.create(@comment.user_pwd)@comment.user_pwd=bcrypted_pwd当用户想要删除他们的评论时,我使用data-confirm-modalgem来确认数据在这部分,我必须解密用户输入的密码以与数据库中的加密密码进行比较我怎样才能解密密码,

  7. ruby - 如何在Elixir中使用AES CBC 128进行加密和解密 - 2

    我在Rails中有一个具有以下方法的应用程序,该方法可以加密和解密文本并与Java客户端通信。defencrypt(string,key)cipher=OpenSSL::Cipher::AES.new(128,:CBC)cipher.encryptcipher.padding=1cipher.key=hex_to_bin(Digest::SHA1.hexdigest(key)[0..32])cipher_text=cipher.update(string)cipher_textexcenddefhex_to_bin(str)[str].pack"H*"enddefbin_to_hex(

  8. ruby-on-rails - 这个 C 和 PHP 程序员如何学习 Ruby 和 Rails? - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。我来自C、php和bash背景,很容易学习,因为它们都有相同的C结构,我可以将其与我已经知道的联系起来。然后2年前我学了Python并且学得很好,Python对我来说比Ruby更容易学。然后从去年开始,我一直在尝试学习Ruby,然后是Rails,我承认,直到现在我还是学不会,讽刺的是那些打着简单易学的烙印,但是对于我这样一个老练的程序员来说,我只是无法将它

  9. ruby-on-rails - 如何生成用于 attr_encrypted 的加密 key - 2

    我正在考虑使用attr_encrypted在Rails应用程序中用于字段级加密的gem。如何生成用于此gem的加密key?更新:Encryptor的文档,它是attr_encrypted使用的底层加密,声明如下(在Usage|Basic下):secret_key=Digest::SHA256.hexdigest('asecretkey')encrypted_value=Encryptor.encrypt('somestringtoencrypt',:key=>secret_key)我猜想key可以是任意长度的随机字符串,而对hexdigest的调用将从中计算出适当的固定长度字符串。这是

  10. ruby - 在Ruby中访问pgp加密文件 - 2

    我有一个pgp加密文件,我需要在运行时从中提取数据。这可以通过仅解密到内存来完成吗(而不是创建解密文件并在完成后将其删除)? 最佳答案 名为OpenPGP的Ruby库几个月前发布。看起来它对你有用。 关于ruby-在Ruby中访问pgp加密文件,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/1083546/

随机推荐