| 加密场景 | 适合什么数据 | 推荐工具/方案 | 一句话 |
|---|---|---|---|
| 数据库字段加密 | 手机号、身份证、银行卡、地址 | MySQL AES_ENCRYPT / pgcrypto / 应用层AES | 数据库内置函数一条SQL批量跑 |
| 数据库透明加密TDE | 整个数据库文件、备份文件 | MySQL TDE / SQL Server TDE / Oracle TDE | 防拖库,对应用层透明 |
| 文件批量加密 | 用户上传的证件照、合同、病历 | OpenSSL / GPG / 应用层AES-GCM | 一行Shell命令批量处理 |
| 传输加密 | 前端到后端传输中的敏感数据 | HTTPS(TLS 1.3) + CryptoJS / Web Crypto API | HTTPS是底线,前端二次加密是加固 |
| 配置/密钥管理 | .env文件、API密钥、数据库密码 | HashiCorp Vault / Ansible Vault / KMS | 密钥不能和密文放一起 |
| 数据脱敏(非加密) | 测试环境、数据分析、演示截图 | 数据库脱敏系统 / 应用层脱敏函数 | 加密和脱敏是两回事,场景完全不同 |
一、数据库字段加密:已经存了几百万条明文数据,怎么批量转成密文
这是最紧迫的场景。数据库跑了三五年,敏感字段全是明文,现在要求整改。MySQL:用内置AES_ENCRYPT()批量加密已有数据
MySQL自带AES加密函数,不需要装任何插件。对一张已有200万行数据的users表,先把phone字段类型从VARCHAR(20)改成VARBINARY(128)(密文是二进制,长度会变),然后一条UPDATE批量跑:
UPDATE users SET phone = AES_ENCRYPT(phone, 'your-256-bit-key');
200万行大概跑5-10分钟。查询时用AES_DECRYPT()解密。注意事项:密钥不要硬编码在SQL里,放环境变量或KMS;MySQL的AES_ENCRYPT默认用ECB模式,安全性不如CBC或GCM,如果对安全性要求高,用应用层AES-GCM替代;加密后like模糊查询就废了,需要额外建一个加密搜索索引(盲索引方案)。
PostgreSQL:pgcrypto扩展
CREATE EXTENSION pgcrypto; 一行开启。提供了PGP对称加密函数(pgp_sym_encrypt() / pgp_sym_decrypt()),比MySQL原生的AES更安全,内置了密钥派生和完整性校验。批量加密同样用UPDATE语句。PostgreSQL还支持列级加密策略(Policy-Based Encryption),可以做到对应用层完全透明。
应用层加密:MyBatis TypeHandler / Django Field / Laravel Casts
不用数据库函数,在ORM层做加密解密。好处是不绑定数据库,换了数据库加密逻辑不变。Java用MyBatis的TypeHandler拦截读写自动加解密,Python Django用自定义Field,PHP Laravel用Eloquent Casts。缺点是模糊查询同样失效,而且每次查询都有解密开销。方案选择:如果只需要在数据库层面防拖库,用数据库内置加密就够;如果需要跨数据库、跨服务统一加密标准,用应用层加密。
二、数据库透明加密TDE:连数据库文件一起保护
字段级加密只能保护你标记的那几个字段,但数据库文件、备份文件、日志文件里可能到处散落着敏感数据的痕迹。TDE在存储引擎层加密整个数据文件,即使有人直接copy走了数据库物理文件,没有密钥也读不了。MySQL TDE:MySQL 5.7+支持InnoDB表空间加密,在my.cnf里配置keyring_file插件和加密密钥路径,然后ALTER TABLE启用加密即可。对应用层完全透明,SELECT/INSERT/UPDATE照常使用。
SQL Server TDE:企业版功能,创建数据库主密钥、创建证书、启用TDE,三步搞定。备份文件也会自动加密。

限制:TDE保护的是"物理文件被盗"这个场景,对"SQL注入拿到数据库查询权限"这个场景完全无效。因为TDE在数据库引擎层面自动解密,攻击者通过SQL查询拿到的还是明文。所以TDE和字段加密是互补关系,不是替代关系。
三、文件批量加密:用户上传的证件照、合同、病历怎么存
方案A:服务器上批量加密已有文件——OpenSSL一行命令
服务器上已经存了几万个用户上传的证件照片,需要批量加密:
find /data/uploads -type f -exec openssl enc -aes-256-cbc -salt -in {} -out {}.enc -pass pass:YOUR_KEY \;
OpenSSL支持AES-256-CBC,加-salt参数防彩虹表攻击。但密钥直接写命令行不安全(会被history记录),生产环境用 -pass file:/path/to/keyfile 从文件读取密钥。
方案B:应用层边上传边加密——代码里集成AES-GCM
更好的做法是不等文件落地再加密,而是在用户上传的瞬间就加密存储。Node.js核心就三行:crypto.createCipheriv('aes-256-gcm', key, iv)创建加密器,然后把文件Buffer传进去加密,最后取authTag做完整性校验。GCM模式比CBC多了一个认证标签,既能加密又能防篡改。Java用Cipher.getInstance("AES/GCM/NoPadding"),Python用cryptography库的AESGCM类。关键原则:每个文件用独立的随机IV(初始化向量),IV可以和密文存一起,但密钥必须单独管理。
文件加密的容易翻车点:加密后的文件无法直接预览。用户想看自己的身份证照片时,需要服务端实时解密再返回。如果并发量大,解密开销会成为瓶颈。解决办法:预览场景生成低分辨率缩略图(缩略图也加密);对热点文件做解密缓存(缓存在内存里,设短过期时间);对于不需要精确查看的场景,用数据脱敏替代解密(比如只显示"张**"而非解密出全名)。
四、传输加密:前端到后端这段路,HTTPS够不够
HTTPS(TLS 1.3)是传输加密的底线,没有商量余地。但有些场景下,光有HTTPS不够:什么时候需要前端再加一层加密
· 经过了CDN/WAF/网关等中间节点,HTTPS在CDN节点解密后到源站可能走HTTP,这中间的数据是明文的。前端用CryptoJS或Web Crypto API加一层AES,即使中间链路泄露,密文也无意义。
· 防止浏览器插件/恶意扩展窃取表单数据,HTTPS保护的是网络传输,但恶意浏览器扩展能在数据离开输入框之前就截获。前端在提交前加密,扩展拿到的就是密文。
· 合规要求,部分行业(金融、医疗、政务)要求"端到端加密",HTTPS只覆盖传输层,前端二次加密才能证明数据在客户端就已被保护。
前端加密推荐用Web Crypto API(浏览器原生,比引入CryptoJS库更安全,密钥不会暴露在JS堆内存中太久)。加密算法选AES-GCM,密钥通过非对称加密(RSA/ECDH)从服务端获取:前端用服务端的公钥加密一个随机生成的对称密钥,服务端用私钥解开后拿到对称密钥,后续通信都用这个对称密钥。

五、加密和脱敏是两回事,搞混了会出大问题
| 对比维度 | 数据加密 | 数据脱敏 |
|---|---|---|
| 能不能还原 | 能,有密钥就能解密 | 不能(不可逆)或部分可逆 |
| 使用场景 | 生产环境存储和传输 | 测试环境、数据分析、演示、外包 |
| 典型操作 | AES加密存储,解密读取 | 138****1234 / 张** / 伪数据替换 |
| 数据可用性 | 解密后完全可用 | 脱敏后格式保留但值不可用 |
| 批量处理工具 | MySQL AES / OpenSSL / GPG | 数据库脱敏系统 / 应用层掩码函数 |
生产环境里的手机号必须用加密(因为用户登录时要发短信验证码,必须能解密出真实号码)。测试环境里的手机号用脱敏(测试人员不需要知道真实号码,只要数据格式和长度跟生产一致就行)。很多人把测试环境的数据直接从生产库copy过去,手机号全是明文,这是等保测评最容易挂的点之一。解决方案:搭建一条"生产到脱敏到测试"的数据流转通道,用静态脱敏工具(数据库自带的数据脱敏功能或第三方脱敏平台)自动对导出的数据做掩码/替换/随机化处理。
六、密钥和配置怎么管:密文再安全,密钥写死在代码里等于没加密
.env文件和配置文件的加密
Ansible Vault:如果你们用Ansible做运维部署,ansible-vault encrypt .env.production 一行命令加密配置文件,部署时用 --ask-vault-pass 输入密码自动解密。配置文件可以安全地放进Git仓库。
HashiCorp Vault:更专业的选择,集中管理所有密钥、数据库密码、API密钥、证书。应用启动时从Vault动态获取密钥,密钥轮换时应用无感知。开源版免费,适合中大型团队。
云KMS:阿里云KMS、腾讯云KMS、AWS KMS,每个云平台都提供密钥管理服务。把主密钥存在KMS里,应用只存一个KMS的访问凭证,需要加密时调KMS接口获取数据密钥。好处是KMS有硬件安全模块(HSM)保护,密钥永远不会离开KMS。
最低要求:密钥绝对不能写死在代码里、不能提交到Git仓库、不能和密文放在同一个数据库里。至少做到"密钥通过环境变量注入"这一步。
密码哈希:bcrypt / argon2
用户密码的加密方式和手机号完全不同。密码不需要解密(只需要验证),所以用哈希而不是加密。目前推荐bcrypt(cost factor至少12)或argon2id(2026年的首选)。MD5和SHA-256哈希密码等同于明文存储,彩虹表一秒破解。如果你们还在用MD5存密码,批量升级方案是用bcrypt重新哈希所有密码:写一个登录兼容逻辑,用户登录时先用旧哈希验证,通过后用bcrypt重新哈希并存为新格式,逐步替换。
七、四套预算方案:从零预算到企业级
零预算方案
数据库:MySQL AES_ENCRYPT() 或 PostgreSQL pgcrypto;文件加密:OpenSSL命令行;传输加密:Let's Encrypt免费SSL证书 + Nginx配置TLS 1.3;密钥管理:环境变量 + .gitignore;密码哈希:bcrypt(各语言标准库自带)。
小团队方案(月成本约500-2000元)
在零预算基础上增加:云KMS管理主密钥(按调用次数付费,量不大时每月几十块);Ansible Vault加密配置文件;前端Web Crypto API做端到端加密;测试环境用开源脱敏工具(如DataMasker或自己写的脱敏脚本)。
中型团队方案(月成本约3000-10000元)
HashiCorp Vault(开源版免费,运维成本是人力);MySQL TDE + 字段级AES-GCM双层加密;应用层TypeHandler/Casts统一加密拦截;静态脱敏平台(商业版或自建ETL脱敏管道);密钥轮换自动化脚本。
企业级方案(等保三级以上)
国密SM4替代AES(等保新规对关键信息基础设施要求国密算法);硬件加密机(HSM)管理根密钥;数据库加密网关(对应用层完全透明,所有SQL自动加解密);动态脱敏网关(不同角色看到不同脱敏级别的数据);全链路审计日志(谁在什么时候解密了什么数据,全部记录)。
加密这件事,最大的坑不是技术选错,而是"加密做了,但密钥和密文放在同一个地方"。数据库加了AES加密,密钥写在config.php里;文件用OpenSSL加密了,密码记在运维的txt里;前端加了一层AES,密钥硬编码在JS里F12就能看到。这些加密在安全审计眼里跟没加密一样。加密的核心从来不是算法,而是密钥管理。如果你只能做一件事来提升数据安全,不是换更强的加密算法,而是把密钥从代码里拿出来,放到一个独立的安全存储里。剩下的事——选AES还是SM4、用数据库函数还是应用层加密、加不加前端二次加密——都是在这个基础上添砖加瓦。
