预共享密钥(PSK,Pre-Shared Key)是 TLS 1.3 引入的重要特性,允许通信双方在握手前共享对称密钥,简化握手流程并提升性能。本文详细介绍 PSK 的原理、使用场景以及 OpenSSL 命令行实战。
什么是 PSK?#
PSK 是一种在 TLS 握手前就共享的对称密钥。在传统 TLS 握手过程中,客户端和服务端需要通过公钥密码学协商出共享密钥;而使用 PSK 时,双方直接使用预先共享的密钥进行加密通信。
PSK 的优势#
- 减少握手延迟:省去公钥协商步骤,缩短握手时间
- 降低计算开销:无需执行昂贵的非对称加密运算
- 适用于特定场景:物联网设备、CDN 加速等对性能要求高的场景
PSK 的使用场景#
- 会话恢复(Session Resumption):TLS 会话恢复本质上使用 PSK
- 物联网设备:计算资源受限的设备间安全通信
- CDN 边缘节点:需要快速建立大量连接的场景
- 内部服务通信:在可信网络中使用对称密钥
PSK 密钥生成#
PSK 密钥通常是 256 位(32 字节)的随机数据。使用 OpenSSL 生成:
1
2
|
# 生成 256 位 PSK 密钥(32 字节 = 64 个十六进制字符)
openssl rand -hex 32
|
输出示例:
1
|
779cfa0b22020c13ae4e841e0c96b1b90b3afa48f6bcb85192f1694156676aac
|
⚠️ 注意:PSK 密钥必须安全存储和传输,不要在代码中硬编码或通过网络明文传输。
OpenSSL s_client PSK 测试#
基础连接测试#
使用 PSK 连接到支持 PSK 的服务器:
1
2
3
4
|
# 使用 PSK 连接到服务器
openssl s_client -connect example.com:443 \
-psk 779cfa0b22020c13ae4e841e0c96b1b90b3afa48f6bcb85192f1694156676aac \
-psk_identity "my-client-identity"
|
参数说明:
-psk:PSK 密钥(十六进制格式,不带 0x 前缀)
-psk_identity:PSK 身份标识,服务端用于查找对应的密钥
PSK 会话复用#
保存 PSK 会话用于复用:
1
2
3
4
5
|
# 保存 PSK 会话
openssl s_client -connect example.com:443 \
-psk 779cfa0b22020c13ae4e841e0c96b1b90b3afa48f6bcb85192f1694156676aac \
-psk_identity "my-client-identity" \
-psk_session session.pem
|
复用会话:
1
2
3
|
# 使用保存的 PSK 会话
openssl s_client -connect example.com:443 \
-psk_session session.pem
|
验证 PSK 握手#
查看握手是否使用了 PSK:
1
2
3
4
|
openssl s_client -connect example.com:443 \
-psk 779cfa0b22020c13ae4e841e0c96b1b90b3afa48f6bcb85192f1694156676aac \
-psk_identity "my-client-identity" \
-debug 2>&1 | grep -i "psk\|cipher"
|
Nginx PSK 配置#
服务端配置 PSK 认证需要使用 OpenSSL 库支持。以下是 Nginx 配置示例:
生成服务端 PSK 密钥#
1
2
|
# 服务端为客户端生成单独的 PSK
openssl rand -hex 32
|
Nginx 配置#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
server {
listen 443 ssl;
server_name psk.example.com;
# 密码套件:仅允许支持 PSK 的套件
ssl_ciphers 'TLS13-AES-256-GCM-SHA384';
ssl_prefer_server_ciphers on;
# PSK 密钥文件(格式:identity:hex-key)
ssl_psk_file /etc/nginx/psk.keys;
ssl_psk_hint "psk-auth";
# 其他 SSL 配置
ssl_certificate /path/to/certificate.pem;
ssl_certificate_key /path/to/private.key;
}
|
PSK 密钥文件格式#
/etc/nginx/psk.keys 文件格式:
1
2
|
my-client-identity:779cfa0b22020c13ae4e841e0c96b1b90b3afa48f6bcb85192f1694156676aac
client2:aa1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456
|
⚠️ 注意:Nginx 的 PSK 支持需要 OpenSSL 1.1.1+ 版本,且需要编译时启用 PSK 支持。
PSK 与 TLS 1.3 0-RTT#
TLS 1.3 的 0-RTT(Zero Round Trip Time)模式与 PSK 密切相关。0-RTT 使用 PSK 允许客户端在首次握手时就发送加密数据。
0-RTT 数据的安全风险#
0-RTT 数据存在重放攻击风险,详见 TLS 1.3 0-RTT 重放攻击与防护。
使用 PSK 启用 0-RTT#
1
2
3
4
|
# 启用 0-RTT(需要 PSK)
openssl s_client -connect example.com:443 \
-early_data /path/to/early_data.txt \
-psk_session session.pem
|
PSK 安全性最佳实践#
1. 密钥管理#
- 使用安全的随机数生成器(OpenSSL rand 命令)
- 定期轮换 PSK 密钥
- 存储时使用安全的密钥管理系统(KMS)
2. 身份验证#
PSK 本身不提供身份验证,建议结合:
- 客户端证书(mTLS)
- 应用层身份验证
- 动态令牌(JWT 等)
3. 前向保密#
PSK 不提供前向保密(PFS),因为密钥是静态的。如需 PFS:
- 定期轮换 PSK
- 结合 Diffie-Hellman 密钥交换
1
2
3
|
# 结合 DH 参数实现部分前向保密
ssl_ciphers 'TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256';
ssl_dhparam /path/to/dhparam.pem;
|
验证 PSK 支持#
检查 OpenSSL 版本是否支持 PSK:
1
2
|
openssl version
openssl s_client -help 2>&1 | grep -q psk && echo "PSK supported"
|
查看支持的密码套件:
1
|
openssl ciphers -s -tls1_3 | tr ':' '\n'
|
PSK 是 TLS 1.3 强大的特性,适用于需要高性能、低延迟的安全通信场景。使用时需注意:
- PSK 密钥必须安全存储和传输
- 0-RTT 模式存在重放攻击风险,需谨慎使用
- 建议结合其他认证机制增强安全性
- 定期轮换 PSK 密钥
参考来源