应用密码零改造方案一
对 userInfo 表的 phone
字段实现加密和解密的完整 MySQL 方案,加密后的数据以字符串形式存储:
一.测试截图
密文显示:
解密显示:
二.实现步骤
1. 确保字段长度足够
由于加密后的字符串可能比原数据更长,需调整 phone
字段长度(例如 varchar(255)
足够存储 AES 加密后的 Base64 字符串):
-- 保持原表结构不变(phone 字段为 varchar(255))
CREATE TABLE `userInfo` (
`card` varchar(255) DEFAULT NULL,
`phone` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
2. 定义加密密钥
在 MySQL 会话中设置用户变量(示例密钥为 my_secret_key_123
,实际生产环境应使用安全密钥):
SET @encryption_key = 'my_secret_key_123'; -- 密钥长度需符合 AES 要求(如 16/24/32 字节)
3. 创建触发器实现自动加密
3.1 INSERT 触发器
插入数据时自动加密 phone
字段并转换为 Base64 字符串:
DELIMITER $$
CREATE TRIGGER before_userInfo_insert
BEFORE INSERT ON userInfo
FOR EACH ROW
BEGIN
-- 加密并转换为 Base64 字符串
SET NEW.phone = TO_BASE64(AES_ENCRYPT(NEW.phone, @encryption_key));
END$$
DELIMITER ;
3.2 UPDATE 触发器
更新数据时自动加密 phone
字段:
DELIMITER $$
CREATE TRIGGER before_userInfo_update
BEFORE UPDATE ON userInfo
FOR EACH ROW
BEGIN
SET NEW.phone = TO_BASE64(AES_ENCRYPT(NEW.phone, @encryption_key));
END$$
DELIMITER ;
4. 查询时自动解密
使用 AES_DECRYPT
和 FROM_BASE64
函数解密数据:
SELECT
card,
CAST(AES_DECRYPT(FROM_BASE64(phone), @encryption_key) AS CHAR) AS decrypted_phone
FROM userInfo;
5. 验证测试
插入加密数据
INSERT INTO userInfo (card, phone)
VALUES ('card_001', '13800138000');
查询数据(明文显示)
SELECT
card,
CAST(AES_DECRYPT(FROM_BASE64(phone), @encryption_key) AS CHAR) AS phone
FROM userInfo;
输出:
+----------+-------------+
| card | phone |
+----------+-------------+
| card_001 | 13800138000 |
+----------+-------------+
6. 完整操作流程示例
步骤 1:插入数据(自动加密)
-- 插入数据(明文)
INSERT INTO userInfo (card, phone) VALUES ('card_002', '13900139000');
-- 直接查询表数据(查看密文)
SELECT * FROM userInfo;
输出(加密后的 Base64 字符串):
+----------+----------------------------------+
| card | phone |
+----------+----------------------------------+
| card_002 | k4lWZ3sD4Tz7X1X8hJjKbQ== | -- 示例值,实际值更长
+----------+----------------------------------+
步骤 2:解密查询
SELECT
card,
CAST(AES_DECRYPT(FROM_BASE64(phone), @encryption_key) AS CHAR) AS phone
FROM userInfo;
输出:
+----------+-------------+
| card | phone |
+----------+-------------+
| card_002 | 13900139000 |
+----------+-------------+
注意事项
-
密钥管理
- 示例中硬编码密钥不安全,生产环境应通过外部配置或密钥管理服务动态注入密钥。
- 密钥需符合 AES 算法要求(如 16/24/32 字节长度)。
-
字段长度
- Base64 编码会增加约 33% 的长度,需确保
phone
字段足够长(如原数据 11 位,加密后至少需varchar(24)
)。
- Base64 编码会增加约 33% 的长度,需确保
-
性能影响
- 高频写入场景中,触发器可能增加数据库负载。
-
编码一致性
- 必须统一使用
TO_BASE64
和FROM_BASE64
确保编码/解码一致。
- 必须统一使用
扩展方案:存储过程管理加密
DELIMITER $$
-- 加密存储过程
CREATE PROCEDURE InsertEncryptedUser(
IN p_card VARCHAR(255),
IN p_phone VARCHAR(255)
)
BEGIN
INSERT INTO userInfo (card, phone)
VALUES (p_card, TO_BASE64(AES_ENCRYPT(p_phone, @encryption_key)));
END$$
-- 解密存储过程
CREATE PROCEDURE GetDecryptedUsers()
BEGIN
SELECT
card,
CAST(AES_DECRYPT(FROM_BASE64(phone), @encryption_key) AS CHAR) AS phone
FROM userInfo;
END$$
DELIMITER ;
-- 调用示例
CALL InsertEncryptedUser('card_003', '15900159000');
CALL GetDecryptedUsers();
总结
操作 | 方法 |
---|---|
自动加密 | 通过 BEFORE INSERT/UPDATE 触发器调用 AES_ENCRYPT + TO_BASE64 |
手动解密 | 查询时使用 FROM_BASE64 + AES_DECRYPT 并转换为 CHAR |
安全增强 | 避免硬编码密钥,结合应用层或外部服务管理密钥 |
按此方案实现后,phone
字段在存储时自动加密为字符串,查询时手动解密,满足字符串存储需求。
以下是触发器相关命令:
#删除触发器
DROP TRIGGER IF EXISTS before_insert_userInfo;
#查看所有触发器
SHOW TRIGGERS LIKE 'userInfo';
希望这篇文章对你有所帮助!如果觉得不错,别忘了点赞收藏哦!