如何从MySQL解密Cakephp3加密数据?

时间:2016-01-15 17:38:00

标签: mysql cakephp encryption cryptography cakephp-3.0

我有一个非常具体的要求,其中某些列需要使用aes_encrypt / aes_decrypt加密。我们需要使用eas来加密SQL级别的信息,以便可以使用其他应用程序或使用查询和aes_encrypt / aes_decrypt直接从MySQL读取。

我们的应用程序是使用CakePHP 3开发的,数据库是MySQL 5.6.25。

我发现并仔细按照所选答案的说明进行操作:Encyption/Decryption of Form Fields in CakePHP 3

现在数据正在加密保存在数据库上...问题是我们仍然需要能够在MySQL上使用aes_decrypt来解密信息并且它返回NULL。

在CakePHP 3上,config / app.php:

'Security' => ['salt' => '1234567890']

然后使用:

加密
Security::encrypt($value, Security::salt());

数据保存在MySQL上,但aes_decrypt()返回NULL

SELECT AES_DECRIPT(address_enc, '1234567890') FROM address;

如何设置CakePHP 3以正确加密信息,以便稍后使用aes_decrypt()在MySQL上解密?

[编辑]

我的MYSQL表:

CREATE TABLE IF NOT EXISTS `address` (
`id` int(11) NOT NULL,
  `address` varchar(255) DEFAULT NULL,
  `address_enc` blob,
  `comment` varchar(255) DEFAULT NULL,
  `comment_enc` blob
) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

注意:地址和评论仅适用于测试。

然后,在CakePHP上,我创建了一个自定义数据库类型:

的src /数据库/类型/ CryptedType.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::salt());
    }

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

SRC /配置/ bootstrap.php中

注册自定义类型。

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

的src /型号/表/ AddressTable.php

最后将加密列映射到已注册的类型,就是这样,从现在开始自动处理所有内容。

use Cake\Database\Schema\Table as Schema;

class AddressTable extends Table
{
    // ...

    protected function _initializeSchema(Schema $table)
    {
        $table->columnType('address_enc', 'crypted');
        $table->columnType('comment_enc', 'crypted');
        return $table;
    }

    // ...
}

2 个答案:

答案 0 :(得分:1)

你真的需要这样做吗?

我不打算讨论将加密数据存储在数据库中的优缺点,但是,尝试在SQL级别解密是一个好主意,是一个应该问的问题。

因此,问问自己是否真的需要这样做,也许最好在应用程序级别实现解密,这可能会使复制的确更容易< / em> Security::decrypt()做了什么,这不仅解密,还包括完整性检查。

只需看看内部Security::decrypt()的作用。

在其他应用程序中重新实现它应该很容易。

小心,你可能会灼伤你的手指!

我绝不是加密专家,所以请将以下内容作为开始工作的基本示例,并特别告知自己可能出现的概念和安全问题!

处理数据的加密/解密而不确切知道你在做什么,一个非常糟糕的主意 - 我不能强调这一点!

在SQL级别解密数据

话虽如此,使用我链接到的可怕(原文如此)答案的示例代码,即使用Security::encrypt()Security::salt()作为加密密钥,默认情况下会离开使用从与自身连接的salt(first 32 bytes of its SHA256 representation)派生的加密密钥以AES-256-CBC模式加密的值。

但并非全部,此外,加密值会获得HMAC哈希值,并且初始化向量会挂起,这样您就不会得到可以直接传递给AES_DECRYPT()的“普通”加密数据。

因此,如果您想在MySQL级别上解密(无论出于何种原因),那么您首先必须设置正确的块加密模式

SET block_encryption_mode = 'aes-256-cbc';

稀疏HMAC散列(前64个字节)和初始化向量(后跟16个字节)

SUBSTRING(`column` FROM 81)

并使用hash('sha256', Security::salt() . Security::salt()) SUBSTRING(`column`, 65, 16) 作为加密密钥,并使用加密值的初始化向量进行解密

SET block_encryption_mode = 'aes-256-cbc';
SELECT
    AES_DECRYPT(
        SUBSTRING(`column` FROM 81), -- the actual encryted data
        'the-encryption-key-goes-here',
        SUBSTRING(`column`, 65, 16) -- the intialization vector
    )
FROM table;

所以最后你会留下像

这样的东西
CAST(AES_DECRYPT(...) AS CHAR)

最后,您可能还想要转换值(AES_DECRYPT()),并删除可能的零填充(不确定<script> $(document).ready(function() { clearInterval(refreshId); $("#windraw").load("../raw/wind.php"); }); $(document).ready(function() { refreshId = setInterval(function() { $("#windraw").load("../raw/wind.php"); $('#winddirneedle').css('rotate', $"#windraw"); }, 5000); }); </script> 是否自动执行此操作。)

数据完整性检查

应该注意的是,加密值前面的HMAC哈希有一个特定的目的,它用于the first 32 bytes,所以只要丢弃它,你就会失去它。为了保持它,你必须在SQL级别上实现(定时攻击安全)HMAC256生成/比较。这导致我们回到初始问题,你真的需要在SQL级别解密吗?

答案 1 :(得分:0)

[解决方案]针对此特定需求的解决方案(我们需要使用eas加密SQL级别的信息,以便可以使用其他应用程序或使用查询和aes_encrypt / aes_decryp直接从MySQL读取)来创建自定义CakePHP中的数据库类型,我们实现了PHP Mcrypt。而不是使用CakePHP加密方法。

现在,我们的CakePHP 3应用程序将信息保存到数据库中,并使用eas_decrypt和aes_encrypt在MySQL / phpMyAdmin级别读取数据。