服务器数据加密怎么做

结论: 服务器数据加密要分成三层来做:传输层用 TLS 1.2/1.3 与外部签发的正式证书保护数据在网络上的流动;存储层用 LUKS/dm-crypt 或云平台提供的云盘加密保护落盘数据;备份层用 GPG 或 OpenSSL 加密后再异地存放。三层之外必须单独解决密钥管理的归属问题,否则加密只是形式。

数据加密常被误认为是"安全等级很高才有必要做的事"。事实上它往往由最朴素的需求驱动:客户要求《个人信息保护法》下的加密存储义务、等保三级要求"重要数据在存储和传输过程中应加密"、数据库备份要放到对象存储上不得不加密、一台笔记本或一块退役硬盘被搬走时不希望数据能被读出来。

数据加密分哪几层?先分清三种状态

数据在任何时刻都处于三种状态之一:传输中(Data in Transit)、静态(Data at Rest)、使用中(Data in Use)。前两种是服务器运维者的常规职责范围,第三种(内存加密、机密计算)截至 2026 年主要依赖 SGX / TEE 等硬件能力,普通业务较少涉及。
状态典型位置推荐技术性能开销落地难度
传输中浏览器↔Nginx、服务间调用TLS 1.3、mTLS 双向认证握手阶段微增,后续对称加密几乎无感低,配证书即可
静态(整盘)系统盘、数据盘LUKS/dm-crypt、云盘加密现代 CPU AES-NI 下 3%~8%中,需处理开机解锁
静态(数据库)MySQL/PostgreSQL 数据文件TDE 透明数据加密、列级加密5%~15%中高,依赖商业/企业版功能
静态(文件级)单个敏感文件GPG、age、openssl enc一次性,无持续开销低
静态(备份)备份包、对象存储GPG 公钥加密、rclone crypt压缩加密时一次性开销低
使用中内存、CPU 处理过程机密计算 / TEE视方案而定高

一个容易被忽略的判断准则:加密解决的是"介质失控",不解决"权限失控"。如果攻击者已经拿到了 root shell,任何自动挂载的加密盘对他都是透明的。因此加密永远要和权限收敛、审计日志配合使用。

传输加密:TLS 证书怎么配到最优

传输加密最常见、性价比最高。目标是:全站 HTTPS、只保留 TLS 1.2 与 1.3、启用 HSTS、优先使用前向安全(Forward Secrecy)的加密套件。

nginx
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name example.com;

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # 只保留现代协议,TLS 1.0/1.1 已于 2021 年被主流浏览器废弃
    ssl_protocols TLSv1.2 TLSv1.3;
    # 优先使用服务端套件顺序,启用前向安全
    ssl_prefer_server_ciphers on;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;
    # 会话缓存,减少重复握手
    ssl_session_cache shared:SSL:50m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;
    # OCSP Stapling,加速证书状态校验
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 1.1.1.1 valid=300s;

    # HSTS:强制浏览器一年内只用 HTTPS(确认全站 HTTPS 后再启用)
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Content-Type-Options nosniff always;
}

# HTTP 全量跳转 HTTPS
server {
    listen 80;
    server_name example.com;
    return 301 https://$host$request_uri;
}

证书获取建议直接用 Let's Encrypt(90 天有效期,自动续期),配合 certbot 一条命令搞定;对内网服务可用私有 CA 自签并以 Ansible 统一下发信任。

bash
# 签发证书(Nginx 插件模式)
apt install -y certbot python3-certbot-nginx
certbot --nginx -d example.com -d www.example.com

# 自动续期已经写进 systemd timer / crontab,可用 dry-run 验证
certbot renew --dry-run
systemctl list-timers | grep certbot

# 校验当前证书链与协议支持
openssl s_client -connect example.com:443 -servername example.com -tls1_3 /dev/null | grep -E "Protocol|Cipher|Verify"
echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates -subject

服务间的内部调用(如 API 网关到微服务)建议升级到双向 TLS(mTLS),即客户端也提供证书。这是零信任架构里"永不信任网络、始终验证身份"的基础能力。证书的安装与续期细节见 服务器怎么配置SSL证书,过期处理见 服务器证书过期怎么处理。

存储加密一:LUKS / dm-crypt 整盘加密

LUKS(Linux Unified Key Setup)是 Linux 上标准的块设备加密方案,底层使用 dm-crypt 与内核 crypto API。它在 CPU 支持 AES-NI 的机器上性能损耗极小。

bash
# 1. 安装工具并确认内核支持
apt install -y cryptsetup
modprobe dm_crypt
cat /proc/crypto | grep -i aes

# 2. 对一块【全新且无数据】的数据盘做加密(会销毁全部数据!)
cryptsetup luksFormat --type luks2 --cipher aes-xts-plain64 --key-size 512 \
           --hash sha512 --iter-time 5000 /dev/vdb

# 3. 打开加密卷(映射为 /dev/mapper/secure_data)
cryptsetup luksOpen /dev/vdb secure_data

# 4. 在映射设备上建文件系统并挂载
mkfs.ext4 /dev/mapper/secure_data
mkdir -p /mnt/secure_data
mount /dev/mapper/secure_data /mnt/secure_data
df -h /mnt/secure_data

# 5. 查看加密卷状态与使用的算法
cryptsetup luksDump /dev/vdb | head -30
cryptsetup status secure_data

开机自动解锁是运维的最大痛点。方案有两种:用密钥文件(适合数据盘,密钥文件放在 root 只读的目录),或用 Clevis + Tang 做网络绑定自动解锁(适合数据中心环境,机器能连到 Tang 服务器才解锁)。

bash
# 生成随机密钥文件并加入 LUKS 的密钥槽(slot)
dd if=/dev/urandom of=/root/.luks_key bs=4096 count=1
chmod 400 /root/.luks_key
cryptsetup luksAddKey /dev/vdb /root/.luks_key

# /etc/crypttab:<映射名> <设备UUID> <密钥文件> <选项>
UUID=$(blkid -s UUID -o value /dev/vdb)
echo "secure_data UUID=${UUID} /root/.luks_key luks,discard" >> /etc/crypttab

# /etc/fstab 自动挂载
echo "/dev/mapper/secure_data /mnt/secure_data ext4 defaults,nofail 0 2" >> /etc/fstab

# 测试:重启后确认自动解锁成功
# cryptsetup luksClose secure_data   # 关闭卷的命令,先卸载文件系统

注意密钥文件绝不能放在被加密的那个卷里,也必须异地备份——丢了密钥文件而 slot 0 的口令也忘了,数据就永久无法恢复。

存储加密二:云盘加密与数据库 TDE

如果你用的是云主机,最省事的方案是直接使用云厂商提供的云盘加密能力:在创建云盘时勾选加密,密钥由 KMS(密钥管理服务)托管,主机侧零性能损耗、零运维负担,且快照与从快照创建的云盘自动继承加密属性。缺点是无法防护"宿主机被攻破"这一层,但对绝大多数合规场景已足够。

数据库层的选择更复杂:

数据库方案版本要求说明
MySQLKeyring 插件 + InnoDB 表空间加密MySQL 5.7+/8.0 社区版逐表空间加密,ALTER TABLE t ENCRYPTION='Y'
MySQLTDE 全量企业版 / Percona / 云 RDS商业版才支持 redo/undo 日志完整加密
PostgreSQLpgcrypto 扩展(列级)所有版本灵活但需改应用 SQL
PostgreSQL云 RDS TDE云厂商托管版一键开启,最省事
SQL Server原生 TDE + Always Encrypted全版本功能最完整
Redis无原生 TDE——靠磁盘加密 + TLS + 网络隔离替代
sql
-- MySQL 8.0 社区版:加载 keyring 插件并对表启用加密
INSTALL PLUGIN keyring_file SONAME 'keyring_file.so';
SET GLOBAL keyring_file_data = '/var/lib/mysql-keyring/keyring';

-- 对已有表开启加密
ALTER TABLE user_profiles ENCRYPTION = 'Y';
-- 验证
SELECT TABLE_SCHEMA, TABLE_NAME, CREATE_OPTIONS
FROM information_schema.TABLES
WHERE CREATE_OPTIONS LIKE '%ENCRYPTION%';
conf
# /etc/mysql/mysql.conf.d/mysqld.cnf 持久化配置
[mysqld]
early-plugin-load = keyring_file.so
keyring_file_data = /var/lib/mysql-keyring/keyring
default_table_encryption = ON

备份加密:GPG 与 OpenSSL 怎么选

备份是最容易泄露的环节——它带着全量数据离开了生产环境,落到对象存储、移动硬盘或异地机房。备份必须加密,且推荐用非对称加密:本地只用公钥,私钥离线保管,即使备份被人拖走也解不开。

bash
# ===== 方案 A:GPG 公钥加密(推荐)=====
# 生成密钥对(私钥务必导出到离线介质)
gpg --full-generate-key --expert
gpg --export -a "backup@company" > /root/backup-pubkey.asc

# 加密一个数据库备份
mysqldump -uroot -p --single-transaction --routines appdb | gzip > /tmp/appdb.sql.gz
gpg --trust-model always -r "backup@company" --encrypt --output /backup/appdb.sql.gz.gpg /tmp/appdb.sql.gz

# 恢复时用私钥解密
gpg --decrypt /backup/appdb.sql.gz.gpg | gunzip | mysql -uroot -p appdb

# ===== 方案 B:OpenSSL 对称加密(简单,但密码只在打包时用到)=====
tar czf - /var/www/html | openssl enc -aes-256-cbc -pbkdf2 -salt -out /backup/web-$(date +%F).tar.gz.enc
# 解密
openssl enc -d -aes-256-cbc -pbkdf2 -in /backup/web-2026-01-01.tar.gz.enc | tar xzf -

上传对象存储时推荐 rclone 的 crypt 远端:它在客户端完成加密后再上传,云服务提供商只看到密文,兼顾了便宜的对象存储与数据自主权。备份策略的整体设计见 服务器数据怎么定时备份。

密钥管理:加密不是终点,密钥放哪儿才是

所有加密方案的价值最终取决于密钥。以下是必须遵守的四条底线:

  • 密钥绝不与密文存放同处。 备份数据的密码写在备份脚本里、密钥文件放在加密盘里,等于没加密。
  • 用 KMS 而非明文配置文件。 云厂商的 KMS(或开源的 HashiCorp Vault)提供密钥托管、访问鉴权、轮换与审计,避免了密钥散落在各台机器上。
  • 定期轮换。 TLS 证书建议 90 天,数据加密主密钥建议 1 年一次(通过 re-encrypt 或 key rotation slot 完成)。
  • 至少两人持有恢复凭据。 避免出现"唯一知道密码的人离职了,备份永远打不开"这类事故。
bash
# LUKS 密钥轮换:新增 key slot → 验证能用 → 删除旧 slot
cryptsetup luksAddKey /dev/vdb --key-file /root/.luks_key_old
cryptsetup luksOpen --test-passphrase --key-slot 1 /dev/vdb && echo "new key OK"
cryptsetup luksKillSlot /dev/vdb 0

# 检查还剩几个可用密钥槽(Slots)
cryptsetup luksDump /dev/vdb | grep -A8 "Key Slot"

常见误区 / 排错提示

  1. 以为启用了 HTTPS 就等于数据都加密了。 HTTPS 只保护链路;日志里明文打印身份证号、数据库裸存密码摘要、备份包不加密,加密依然是失败的。
  2. 把加密轮的口令写进 /etc/rc.local 或备份脚本明文参数。 明文口令出现在进程列表(ps aux)里任何人可读,应使用 stdin 或 --key-file。
  3. LUKS 格式化命令打错设备名,把系统盘清空了。 执行 luksFormat 前务必用 lsblk / blkid 三次确认设备名,且务必先做快照。
  4. 加密后忘了测恢复。 没有演练过的备份等于没有备份。每季度必须做一次"从加密备份完整还原到新机器"的演练并记录耗时。
  5. 保留 TLS 1.0/1.1 "兼容老客户"。 截至 2026 年,主流浏览器早已废弃旧协议,保留它们只会拉低整体安全评级(PCI DSS 与等保测评都会扣分)。
  6. 数据库开了 TDE 就不再做应用层脱敏。 TDE 防的是文件层面的泄露,运维人员或有权限的应用依然能读到明文,敏感字段仍需应用层加密或脱敏展示。