在数据库存储场景中,用户手机号、身份证号、银行卡号等敏感信息如果明文存储,一旦出现数据泄露会造成严重后果。很多开发者会问SQL语言怎样实现数据加密存储,其实主流关系型数据库都提供了原生的加密函数和安全机制,只需要合理运用就能完成敏感信息的加密存储。

SQL加密存储的核心函数
不同数据库提供的加密函数语法略有区别,下面分别介绍MySQL和PostgreSQL的常用加密方式。
MySQL的加密函数
MySQL提供了AES_ENCRYPT()和AES_DECRYPT()函数用于AES对称加密,还支持MD5()、SHA2()等哈希函数,不过哈希函数一般用于密码校验,不适合需要解密回原文的敏感信息存储。
-- 创建测试表,存储加密后的敏感信息
CREATE TABLE user_info (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
-- 加密后的手机号字段,类型为VARBINARY适配二进制加密结果
encrypted_phone VARBINARY(255) NOT NULL,
-- 加密后的身份证号字段
encrypted_id_card VARBINARY(255) NOT NULL
);
-- 插入数据时使用AES_ENCRYPT加密,密钥自定义,这里用'my_secret_key'示例
INSERT INTO user_info (username, encrypted_phone, encrypted_id_card)
VALUES (
'张三',
AES_ENCRYPT('13800138000', 'my_secret_key'),
AES_ENCRYPT('110101199001011234', 'my_secret_key')
);
-- 查询时解密数据,需要传入和加密一致的密钥
SELECT
username,
AES_DECRYPT(encrypted_phone, 'my_secret_key') AS phone,
AES_DECRYPT(encrypted_id_card, 'my_secret_key') AS id_card
FROM user_info;PostgreSQL的加密函数
PostgreSQL需要提前安装pgcrypto扩展才能使用加密函数,常用的有pgp_sym_encrypt()和pgp_sym_decrypt()用于对称加密。
-- 安装pgcrypto扩展
CREATE EXTENSION IF NOT EXISTS pgcrypto;
-- 创建测试表
CREATE TABLE user_info (
id SERIAL PRIMARY KEY,
username VARCHAR(50) NOT NULL,
encrypted_phone BYTEA NOT NULL,
encrypted_id_card BYTEA NOT NULL
);
-- 插入加密数据,使用AES128对称加密
INSERT INTO user_info (username, encrypted_phone, encrypted_id_card)
VALUES (
'李四',
pgp_sym_encrypt('13900139000', 'my_secret_key'),
pgp_sym_encrypt('120101199002022345', 'my_secret_key')
);
-- 查询时解密数据
SELECT
username,
pgp_sym_decrypt(encrypted_phone, 'my_secret_key') AS phone,
pgp_sym_decrypt(encrypted_id_card, 'my_secret_key') AS id_card
FROM user_info;字段级加密的注意事项
使用SQL实现加密存储时,需要注意以下几点:
- 加密后的字段是二进制类型,不能使用普通的VARCHAR存储,否则会出现乱码或者数据截断问题,MySQL用VARBINARY,PostgreSQL用BYTEA。
- 加密密钥需要妥善管理,不要硬编码在SQL语句中,最好通过应用层传递,或者使用数据库的密钥管理功能,避免密钥泄露导致加密失效。
- 加密字段无法直接使用索引进行范围查询,只能做等值查询,如果业务需要按加密字段查询,需要考虑额外的处理方案。
哈希与加密的选择
很多开发者会混淆哈希和加密的概念,这里需要明确两者的适用场景:
| 技术类型 | 是否可逆 | 适用场景 |
|---|---|---|
| 对称加密(如AES) | 可逆,用密钥可以解密回原文 | 需要还原原文的敏感信息,如手机号、身份证号 |
| 哈希(如SHA256) | 不可逆,无法从哈希值得到原文 | 不需要还原的场景,如用户密码存储,校验时对比哈希值即可 |
如果是存储用户密码,不建议用加密的方式,而是用带盐的哈希函数,比如MySQL的SHA2('密码' + '盐值', 256),这样即使数据库泄露,攻击者也无法反向得到明文密码。
综合应用示例
下面是一个完整的MySQL场景示例,同时包含加密存储和哈希存储的用法:
-- 创建用户表,同时存储加密的联系方式和哈希后的密码
CREATE TABLE sys_user (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL UNIQUE,
-- 密码用SHA256哈希存储,加盐处理
password_hash CHAR(64) NOT NULL,
-- 加密后的手机号
encrypted_phone VARBINARY(255),
-- 加密后的邮箱
encrypted_email VARBINARY(255),
salt VARCHAR(32) NOT NULL
);
-- 插入用户数据,假设盐值为'random_salt_123'
SET @salt = 'random_salt_123';
SET @encrypt_key = 'my_secret_key';
INSERT INTO sys_user (username, password_hash, encrypted_phone, encrypted_email, salt)
VALUES (
'test_user',
SHA2(CONCAT('test_password', @salt), 256),
AES_ENCRYPT('13800138000', @encrypt_key),
AES_ENCRYPT('test@ippipp.com', @encrypt_key),
@salt
);
-- 用户登录时校验密码
SET @input_password = 'test_password';
SELECT COUNT(*) AS is_valid FROM sys_user
WHERE username = 'test_user'
AND password_hash = SHA2(CONCAT(@input_password, salt), 256);
-- 查询用户信息时解密敏感字段
SELECT
username,
AES_DECRYPT(encrypted_phone, @encrypt_key) AS phone,
AES_DECRYPT(encrypted_email, @encrypt_key) AS email
FROM sys_user WHERE username = 'test_user';只要合理运用SQL提供的加密函数,结合自身业务的安全需求选择合适的技术方案,就可以有效实现敏感信息的加密存储,降低数据泄露带来的风险。