【问题标题】:Search LIKE with AES_ENCRYPT and AES_DECRYPT in mysql在 mysql 中使用 AES_ENCRYPT 和 AES_DECRYPT 搜索 LIKE
【发布时间】:2018-08-05 01:48:15
【问题描述】:

我使用这种技术来加密我的数据库的某些字段:
How to use AES_ENCRYPT and AES_DECRYPT in mysql

效果很好,但我遇到了问题。
现在字段的内容是加密的,我不能用经典的方式做 LIKE !

我尝试对解密字段执行类似操作,但 sql 无法识别该字段!!
这是结构(非常简单):

CREATE TABLE `messages` (
  `id` int(11) NOT NULL,
  `message` varchar(250) NOT NULL,
  `crypt_key` varchar(50) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

ALTER TABLE `messages`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=1;

插入:

INSERT into messages (message) VALUES (AES_ENCRYPT('Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. ', '123456'));

简单选择:

SELECT 
       CAST(AES_DECRYPT(message, '123456') AS CHAR(50)) decrypt 
FROM  messages 

完美,一切正常!


现在,假设我想在“消息”字段中使用 LIKE 进行搜索:

SELECT 
       CAST(AES_DECRYPT(message, '123456') AS CHAR(50)) decrypt 
FROM  messages WHERE decrypt LIKE '%Lorem%'

我收到此错误:

Unknown 'decrypt' field in where clause

这个查询同样的错误:

SELECT 
       CAST(AES_DECRYPT(message, '123456') AS CHAR(50)) AS decrypt 
FROM  messages WHERE decrypt.message LIKE '%Lorem%'

原则上,我有消息加密,解密密钥和解密算法!应该可以在解密字段中通过 sql 搜索,但我找不到解决方案。

使用请求堆栈?但这不是很优化...

我接受任何解决方案和任何意见!

【问题讨论】:

  • 尝试 HAVING 而不是 WHERE。您不能在 WHERE 子句中使用列别名。
  • 哇!它工作得很好=)我会了解它
  • 但是有很大的不同。如果您使用 HAVING,则孔结果将最终确定,然后使用您的 HAVING 进行过滤。您也可以像这样使用 WHERE 中的函数:SELECT CAST(AES_DECRYPT(message, '123456') AS CHAR(50)) AS decrypt FROM messages WHERE CAST(AES_DECRYPT(message, ' 123456') AS CHAR(50)) LIKE '%Lorem%'; 。但是以 % 开头的 Like 始终是 FULL TABLE SCAN
  • @BerndBuffen 性能完全相同,因为无论哪种方式都需要全表扫描。那么为什么要写两次相同的表达式呢?
  • MySQL 内部加密不是很好,对任何实际敏感的数据都没有好处。 MySQL 和各种服务器日志将记录加密前后的未加密数据,然后再次解密。您希望在数据到达 MySQL 引擎之前进行加密。

标签: mysql database encryption aes sql-like


【解决方案1】:

WHERE 子句中不允许使用列别名。但是你可以在 HAVING 子句中使用它们:

SELECT CAST(AES_DECRYPT(message, '123456') AS CHAR(50)) decrypt 
FROM messages
HAVING decrypt LIKE '%Lorem%'

您也可以只复制完整的表达式并在 WHERE 子句中使用它(就像在 cmets 中建议的 Bernd Bufen):

SELECT CAST(AES_DECRYPT(message, '123456') AS CHAR(50)) decrypt 
FROM messages
HAVING CAST(AES_DECRYPT(message, '123456') AS CHAR(50)) LIKE '%Lorem%'

但我没有看到这里代码重复的原因。性能应该是一样的,因为表扫描会以任何一种方式执行。

【讨论】:

    【解决方案2】:

    这不是答案。它只适用于@Paul Spiegel。

    最大的区别是 HAVING 首先创建一个结果集 所有 ROW,然后它使用 HAVING 子句过滤结果。 因此 Query 将占用更多内存来存储第一个结果。

    如果你使用 WHERE 子句,它也是一个全表扫描,但 mysql 只放 结果集中的结果行。

    查看示例。我创建了一个只有 1000 行的表,并且字符串中只有每 10 行有一个“LOREM”。请参阅 EXPLAIN 中的“已过滤”列。

    mysql> select id,CAST(message AS CHAR(20)) from messages limit 10;
    +----+---------------------------+
    | id | CAST(message AS CHAR(20)) |
    +----+---------------------------+
    |  1 | Lorem ipsum dolor si      |
    |  2 | XXXXX ipsum dolor si      |
    |  3 | XXXXX ipsum dolor si      |
    |  4 | XXXXX ipsum dolor si      |
    |  5 | XXXXX ipsum dolor si      |
    |  6 | XXXXX ipsum dolor si      |
    |  7 | XXXXX ipsum dolor si      |
    |  8 | XXXXX ipsum dolor si      |
    |  9 | XXXXX ipsum dolor si      |
    | 10 | XXXXX ipsum dolor si      |
    +----+---------------------------+
    10 rows in set, 10 warnings (0,00 sec)
    
    mysql> EXPLAIN SELECT
        ->        message  decrypt
        -> FROM  messages
        -> HAVING decrypt LIKE '%LOREM%';
    +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------+
    | id | select_type | table    | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
    +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------+
    |  1 | SIMPLE      | messages | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 1000 |   100.00 | NULL  |
    +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------+
    1 row in set, 1 warning (0,00 sec)
    
    mysql>
    mysql> EXPLAIN SELECT
        ->        message  decrypt
        -> FROM  messages
        -> WHERE message LIKE '%LOREM%';
    +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
    | id | select_type | table    | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
    +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
    |  1 | SIMPLE      | messages | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 1000 |    11.11 | Using where |
    +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
    1 row in set, 1 warning (0,00 sec)
    
    mysql>
    

    【讨论】:

    • 不要混淆逻辑评估顺序、MySQL 是如何解析查询以及查询是如何执行的。如果具有条件不匹配,则无需从行中选择任何内容。运行以下查询:select @v := concat(@v, 'select;') from (select @v := 'from;') t having (@v := concat(@v, 'having;'))+1;rextester - 你会看到,SELECT 子句在 HAVING 子句之后被评估/执行。我已经在百万行表上运行了测试 - 并且没有性能差异。 ..
    • .. EXPLAIN 结果中的过滤列仅对 JOIN 查询有用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-03
    • 2023-03-10
    • 2013-01-03
    • 2013-05-09
    相关资源
    最近更新 更多