首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >符号学4-加密/解密字段使用的理论与服务?

符号学4-加密/解密字段使用的理论与服务?
EN

Stack Overflow用户
提问于 2018-10-02 23:13:56
回答 2查看 10.1K关注 0票数 4

所以我的数据库中有一个实体中的字段

代码语言:javascript
复制
class Person
{
    // other fields

    /**
     * @var string
     *
     * @ORM\Column(name="last_name", type="string", length=50, nullable=false)
     */
    private $lastName;

    /**
     * @var string
     *
     * @ORM\Column(name="first_name", type="string", length=50, nullable=false)
     */
    private $firstName;

   // getters and setters
}

我有一个叫SecureEncryptor的服务。它具有解密()和Encrypt()函数--基本上,您只需将加密/未加密(分别)的字符串传递给它,它就会执行以下操作。

问题是,我不知道如何与实体一起使用该服务--特别是在考虑表单(类型)时。我的意思是,我知道我只需要得到字段并调用Decrypt函数,但是对于绑定到Person实体的Type,这是行不通的。

我开始为被解密的人创建一个单独的实体,然后我会在处理数据库的时候切换它,但这似乎是错误的。我的另一个想法是从实体中调用服务,但我也读到这是错误的。

有什么想法吗?

编辑:

这基本上就是我想要做的:

代码语言:javascript
复制
$builder->get('dateOfBirth')
   ->addModelTransformer(new CallbackTransformer(
       function ($encryptedDOB) {
           return $this->encryptor->decrypt($encryptedDOB, salt); // How do I get the salt value here?
       },
      function ($decryptedDOB) {
         return $this->encryptor->encrypt($decryptedDOB, salt); // How do I get the salt value here?
      }
 ));

或者在这一步之前对数据进行解密/加密,但不确定如何实现。

编辑2:

我找到了,它显示您可以在PRE_SET_DATA事件中访问实体数据,但是您不能在其中添加一个数据转换器,所以不确定它如何工作。

EN

回答 2

Stack Overflow用户

发布于 2018-10-05 07:07:47

在经历了三天的混乱--可能是20+几个小时的挫折--之后,我终于找到了正确的方法。实体事件侦听器

所以我做了以下修改

app\config\services.yaml

代码语言:javascript
复制
parameters:
    ...
    encryption_key: '%kernel.project_dir%/path/to/my/key'

services:
    ...
    App\EventListeners\PatientListener:
        arguments: [@session]
        tags:
            - { name: doctrine.event_listener, event: prePersist }
            - { name: doctrine.event_listener, event: preUpdate }
            - { name: doctrine.event_listener, event: postLoad }

然后我做了服务

代码语言:javascript
复制
<?php

namespace App\EventListeners;

use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
use App\Entity\Patients;
use ParagonIE\Halite\HiddenString;
use ParagonIE\Halite\KeyFactory;
use ParagonIE\Halite\Symmetric\Crypto as Symmetric;
use ParagonIE\Halite\Symmetric\EncryptionKey;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\HttpFoundation\Session\Session;

class PatientListener
{
    private $params;
    private $session;
    private $logger;

    public function __construct(ParameterBagInterface $params, 
                                 Session $session, LoggerInterface $logger)
    {
        $this->params = $params;
        $this->session = $session;
        $this->logger = $logger;
    }

    public function prePersist(LifecycleEventArgs $args)
    {
        $entity = $args->getObject();

        if ($entity instanceof Patients)
        {
            $this->encryptFields($entity);
        }
    }

    public function preUpdate(LifecycleEventArgs $args)
    {
        $entity = $args->getObject();

        if ($entity instanceof Patients)
        {
            $this->encryptFields($entity);
        }
    }

    public function postLoad(LifecycleEventArgs $args)
    {
        $entity = $args->getObject();

        if ($entity instanceof Patients)
        {
            $this->decryptFields($entity);
        }
    }

    private function loadKey() : EncryptionKey
    {
        try
        {
            KeyFactory::loadEncryptionKey($this->params->get('encryption_key'));
        }
        catch(\Throwable $e)
        {
            $this->session->getFlashBag()->add('danger', 'Unable to load encryption key!');
            $this->logger->emergency(
                'Unable to lod the encryption key!', array(
                'error' => $e->getMessage(),
            ));
            throw;
        }
    }

    private function encryptFields(Patients $patient)
    {
        $key = $this->loadKey();

        // Encrypt the variables
        $lastName = $this->encrypt('Last Name', $patient->getLastName(), $key);

        // Set the entity variables
        $patient->setLastName($lastName);

        return $patient;
    }

    private function encrypt($fieldName, $value, $key)
    {
        try {
            return Symmetric::encrypt(
                new HiddenString($value),
                $key
            );
        } catch(\Throwable $e)
        {
            $this->session->getFlashBag()->add('danger', 'Unable to encrypt field');
            $this->logger->critical(
                'Unable to encrypt field "'.$fieldName.'" in Patients entity. DB update terminated.', array(
                'error' => $e->getMessage(),
            ));
            throw;
        }

    }

    private function decryptFields(Patients $patient)
    {
        $key = $this->loadKey();
        $id = $patient->getId();

        // Decrypt the variables
        $lastName = $this->decrypt($id, 'Last Name', $patient->getLastName(), $key);

        // Set the entity variables
        $patient->setLastName($lastName);
    }

    private function decrypt($id, $fieldName, $value, $key)
    {
        try
        {
            return Symmetric::decrypt($value, $key);
        }
        catch (\Throwable $e)
        {
            $this->session->getFlashBag()->add('warning', 'Unable to decrypt field');
            $this->logger->warning(
                'Unable to decrypt field "'.$fieldName.'" in Patients entity for ID: '.$id, array(
                'error' => $e->getMessage(),
            ));
        }
    }
}

现在,数据被加载到数据库时被加密,当数据加载到实体时被解密。

这种方法是正确的,因为这样做的任何其他方式(自定义原则类型,数据转换器,做它在控制器等)。如果其他人在另一个控制器中创建另一个表单或使用该实体,则总是有可能使数据解密(也就是非常糟糕)。这种方法确保数据始终通过理论被正确加密和解密(除非您做了一些定制的DQL\SQL,在这种情况下,您可能需要自己处理,这取决于您正在做什么)。

票数 9
EN

Stack Overflow用户

发布于 2018-10-03 06:09:13

如果我正确理解,您将寻找以透明方式在数据库中加载/存储加密数据的方法。我想我应该在加载/保存时在这里实现风俗主义类型和解密/加密。

编辑:不难实现,作为基础,您可以使用Doctrine\DBAL\Types\TextType,您将扩展,在那里您感兴趣的convertToPHPValue() -解密和convertToDatabaseValue()加密。更多的样本,看看和原则类型,定义,并找到一个最适合你的需要。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52617635

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档