搜 索

openssl从入门到放弃

  • 38阅读
  • 2024年03月04日
  • 0评论
首页 / 编程 / 正文

什么是OpenSSL

OpenSSL是一个功能强大的安全套接字层密码库,诞生于1998年——那时候Google还在车库里,而OpenSSL已经在默默守护互联网安全了。

它能干啥

功能模块作用人话翻译
密码算法库RSA、AES、SHA等加密算法把数据变成乱码
SSL/TLS协议库实现安全通信协议让数据传输不裸奔
命令行工具各种证书、密钥操作运维人员的瑞士军刀

OpenSSL的江湖地位

全球90%以上的HTTPS网站 ──使用──▶ OpenSSL

没错,你每天访问的淘宝、微信、银行网站,背后大概率都有OpenSSL在保驾护航。它就像互联网的空气——平时感觉不到,但没有它你会窒息。


核心概念速通

在开始敲命令之前,先搞清楚几个概念,不然后面会一脸懵:

┌─────────────────────────────────────────────────────────────┐
│                        证书信任链                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   ┌──────────────┐                                          │
│   │   根证书CA    │  ◀── 浏览器/系统内置信任                  │
│   │ (Root CA)    │                                          │
│   └──────┬───────┘                                          │
│          │ 签发                                              │
│          ▼                                                  │
│   ┌──────────────┐                                          │
│   │  中间证书CA   │  ◀── 由根CA签发                          │
│   │(Intermediate)│                                          │
│   └──────┬───────┘                                          │
│          │ 签发                                              │
│          ▼                                                  │
│   ┌──────────────┐                                          │
│   │  服务器证书   │  ◀── 你的网站用的就是这个                  │
│   │ (Server Cert)│                                          │
│   └──────────────┘                                          │
│                                                             │
└─────────────────────────────────────────────────────────────┘

关键术语

术语英文一句话解释
私钥Private Key绝对不能泄露的钥匙,用来解密和签名
公钥Public Key可以公开的钥匙,用来加密和验签
证书Certificate公钥 + 身份信息 + CA签名,相当于"数字身份证"
CSRCertificate Signing Request证书签名请求,找CA申请证书用的
CACertificate Authority证书颁发机构,负责"发身份证"的权威部门
PEMPrivacy Enhanced Mail一种证书编码格式,Base64文本,以-----BEGIN开头
DERDistinguished Encoding Rules二进制证书格式
PKCS#12/PFX-把证书和私钥打包在一起的格式,常见于Windows

第一章:生成密钥对

生成RSA私钥

# 方式1:生成2048位RSA私钥(推荐)
openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048

# 方式2:老命令,效果一样
openssl genrsa -out private_key.pem 2048

# 方式3:生成带密码保护的私钥(更安全)
openssl genpkey -algorithm RSA -out private_key.pem -aes256 -pkeyopt rsa_keygen_bits:2048
# 会提示你输入密码,以后每次使用私钥都要输入
💡 2048 vs 4096:2048位目前够用,4096更安全但更慢。就像门锁,普通防盗门够用了,没必要装银行金库的门。

从私钥提取公钥

openssl rsa -pubout -in private_key.pem -out public_key.pem

查看密钥信息

# 查看私钥详情(会显示模数、指数等数学参数)
openssl rsa -in private_key.pem -text -noout

# 查看公钥详情
openssl rsa -pubin -in public_key.pem -text -noout

生成ECC密钥(更现代的选择)

# ECC比RSA更短更快,256位ECC ≈ 3072位RSA的安全性
openssl ecparam -genkey -name prime256v1 -out ec_private.pem

# 提取公钥
openssl ec -in ec_private.pem -pubout -out ec_public.pem

第二章:创建自签名证书

自签名证书就是"自己给自己发身份证",浏览器不信任,但开发测试够用了。

一步到位生成证书

# 生成私钥 + 自签名证书,一条命令搞定
openssl req -x509 -newkey rsa:2048 -keyout private_key.pem -out cert.pem -days 365 -nodes

# 参数解释:
# -x509      : 生成自签名证书(不是CSR)
# -newkey    : 同时生成新私钥
# -keyout    : 私钥输出文件
# -out       : 证书输出文件
# -days 365  : 有效期365天
# -nodes     : 私钥不加密(No DES),生产环境别用这个

交互式填写证书信息

运行上面的命令后,会让你填一堆信息:

Country Name (2 letter code) [AU]: CN
State or Province Name (full name) [Some-State]: Guangdong
Locality Name (eg, city) []: Shenzhen
Organization Name (eg, company) []: My Company
Organizational Unit Name (eg, section) []: IT Department
Common Name (e.g. server FQDN or YOUR name) []: localhost
Email Address []: admin@example.com
⚠️ Common Name很重要:这个要填你的域名,比如www.example.com,填错了浏览器会报证书不匹配。

非交互式生成(脚本党福音)

openssl req -x509 -newkey rsa:2048 \
    -keyout private_key.pem \
    -out cert.pem \
    -days 365 \
    -nodes \
    -subj "/C=CN/ST=Guangdong/L=Shenzhen/O=MyCompany/CN=localhost"

生成带SAN的证书(支持多域名)

现代浏览器要求证书必须有SAN(Subject Alternative Name),不然会报错:

# 创建配置文件
cat > san.cnf << EOF
[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn
req_extensions = req_ext

[dn]
C = CN
ST = Guangdong
L = Shenzhen
O = MyCompany
CN = localhost

[req_ext]
subjectAltName = @alt_names

[alt_names]
DNS.1 = localhost
DNS.2 = *.localhost
DNS.3 = myapp.local
IP.1 = 127.0.0.1
IP.2 = 192.168.1.100
EOF

# 生成证书
openssl req -x509 -newkey rsa:2048 \
    -keyout private_key.pem \
    -out cert.pem \
    -days 365 \
    -nodes \
    -config san.cnf \
    -extensions req_ext

第三章:证书的日常操作

查看证书信息

# 查看证书详情(最常用)
openssl x509 -in cert.pem -text -noout

# 只看有效期
openssl x509 -in cert.pem -dates -noout

# 只看主题和颁发者
openssl x509 -in cert.pem -subject -issuer -noout

# 查看证书指纹
openssl x509 -in cert.pem -fingerprint -sha256 -noout

验证证书

# 验证证书链
openssl verify -CAfile ca_bundle.pem cert.pem

# 检查证书和私钥是否匹配
openssl x509 -noout -modulus -in cert.pem | openssl md5
openssl rsa -noout -modulus -in private_key.pem | openssl md5
# 两个MD5值相同说明匹配

格式转换大全

证书格式转换是运维的日常噩梦,这里整理一份速查表:

# PEM → DER
openssl x509 -in cert.pem -outform DER -out cert.der

# DER → PEM
openssl x509 -in cert.der -inform DER -outform PEM -out cert.pem

# PEM → PKCS#12(把证书和私钥打包,常用于导入Windows/Java)
openssl pkcs12 -export -out cert.pfx -inkey private_key.pem -in cert.pem -certfile ca_bundle.pem

# PKCS#12 → PEM(从pfx中提取)
openssl pkcs12 -in cert.pfx -out cert.pem -nodes

# 提取证书链中的各个证书
openssl crl2pkcs7 -nocrl -certfile chain.pem | openssl pkcs7 -print_certs -out all_certs.pem

检查远程服务器证书

# 查看网站证书(神器命令!)
echo | openssl s_client -connect www.baidu.com:443 -servername www.baidu.com 2>/dev/null | openssl x509 -text -noout

# 只看证书有效期
echo | openssl s_client -connect www.baidu.com:443 2>/dev/null | openssl x509 -dates -noout

# 检查证书链完整性
openssl s_client -connect www.baidu.com:443 -showcerts

第四章:SSL/TLS通信测试

启动测试服务器

# 启动HTTPS服务器(监听4433端口)
openssl s_server -cert cert.pem -key private_key.pem -port 4433 -www

# -www参数会返回一个简单的HTTP响应,可以用浏览器访问 https://localhost:4433

测试客户端连接

# 连接服务器
openssl s_client -connect localhost:4433

# 连接时指定SNI(Server Name Indication)
openssl s_client -connect localhost:4433 -servername mysite.com

# 测试特定TLS版本
openssl s_client -connect localhost:4433 -tls1_2
openssl s_client -connect localhost:4433 -tls1_3

# 查看支持的加密套件
openssl s_client -connect localhost:4433 -cipher 'ALL' 2>/dev/null | grep -E 'Cipher|Protocol'

压测SSL性能

# 测试RSA签名性能
openssl speed rsa2048

# 测试AES加密性能
openssl speed aes-256-gcm

# 测试完整握手性能
openssl s_time -connect localhost:4433 -new -time 10

第五章:Let's Encrypt —— 免费证书的救星

"以前SSL证书要花几千块,现在Let's Encrypt让它白菜价。" —— 全球站长

Let's Encrypt是什么

Let's Encrypt是一个免费、自动化、开放的证书颁发机构(CA),由互联网安全研究小组(ISRG)运营。

优点

  • 🆓 完全免费
  • 🤖 自动化续期
  • ⚡ 签发速度快(几秒钟)
  • 🌍 被所有主流浏览器信任

限制

  • 证书有效期只有90天(必须自动续期)
  • 只支持域名验证(DV),不支持企业验证(OV/EV)
  • 每个域名每周最多签发50张证书

证书申请流程

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│  1.安装Certbot │────▶│ 2.验证域名所有权│────▶│  3.获取证书   │
└─────────────┘     └─────────────┘     └─────────────┘
                           │
            ┌──────────────┼──────────────┐
            ▼              ▼              ▼
      HTTP-01验证     DNS-01验证    TLS-ALPN-01验证
     (放文件到网站)   (添加DNS记录)   (TLS握手验证)

安装Certbot

# Ubuntu/Debian
sudo apt update
sudo apt install certbot

# CentOS/RHEL
sudo yum install epel-release
sudo yum install certbot

# macOS
brew install certbot

# 或者用pip(通用)
pip install certbot

方式一:Standalone模式(最简单)

适合没有Web服务器或者可以临时停掉的情况:

# 申请证书(会临时启动一个Web服务器在80端口)
sudo certbot certonly --standalone -d example.com -d www.example.com

# 证书会保存在:
# /etc/letsencrypt/live/example.com/fullchain.pem  (证书链)
# /etc/letsencrypt/live/example.com/privkey.pem    (私钥)

方式二:Webroot模式(不停服务)

如果Web服务器正在运行,不想停:

# 指定网站根目录,Certbot会在里面放验证文件
sudo certbot certonly --webroot -w /var/www/html -d example.com -d www.example.com

需要确保Web服务器能响应 http://example.com/.well-known/acme-challenge/ 路径。

方式三:DNS验证(支持通配符)

申请通配符证书(*.example.com)必须用DNS验证:

sudo certbot certonly --manual --preferred-challenges dns -d "*.example.com" -d example.com

运行后会提示你添加一条TXT记录:

Please deploy a DNS TXT record under the name:
_acme-challenge.example.com
with the following value:
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

去域名DNS管理后台添加这条记录,然后继续。

方式四:配合Nginx自动配置

# 自动配置Nginx(最省心)
sudo certbot --nginx -d example.com -d www.example.com

# Certbot会自动:
# 1. 申请证书
# 2. 修改Nginx配置
# 3. 配置自动跳转HTTPS

方式五:配合Apache

sudo certbot --apache -d example.com -d www.example.com

自动续期

Let's Encrypt证书90天过期,必须设置自动续期:

# 测试续期(不会真的续)
sudo certbot renew --dry-run

# 手动续期
sudo certbot renew

# 设置定时任务自动续期
# 方式1:Certbot自带的timer(推荐)
sudo systemctl enable certbot.timer
sudo systemctl start certbot.timer

# 方式2:crontab
# 每天凌晨3点检查并续期
echo "0 3 * * * root certbot renew --quiet --post-hook 'systemctl reload nginx'" | sudo tee /etc/cron.d/certbot-renew

Nginx配置示例

server {
    listen 80;
    server_name example.com www.example.com;
    
    # 强制跳转HTTPS
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name example.com www.example.com;
    
    # Let's Encrypt证书
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    
    # SSL优化配置
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;
    
    # HSTS(可选,开启后浏览器会强制HTTPS)
    add_header Strict-Transport-Security "max-age=63072000" always;
    
    # ... 其他配置
}

acme.sh —— 更轻量的替代品

如果觉得Certbot太重,可以用acme.sh:

# 安装
curl https://get.acme.sh | sh

# 申请证书(DNS API方式,以Cloudflare为例)
export CF_Key="你的Cloudflare API Key"
export CF_Email="你的邮箱"
acme.sh --issue --dns dns_cf -d example.com -d "*.example.com"

# 安装证书到Nginx
acme.sh --install-cert -d example.com \
    --key-file /etc/nginx/ssl/example.com.key \
    --fullchain-file /etc/nginx/ssl/example.com.pem \
    --reloadcmd "systemctl reload nginx"

第六章:常见踩坑与排错

坑1:证书链不完整

症状:浏览器报"证书不受信任",但证书明明是正规CA签发的。

原因:服务器只配了服务器证书,没配中间证书。

解决

# 把中间证书和服务器证书合并
cat server.pem intermediate.pem > fullchain.pem

# Nginx配置使用fullchain
ssl_certificate /path/to/fullchain.pem;

坑2:私钥和证书不匹配

症状:Nginx启动报错 SSL_CTX_use_PrivateKey_file failed

诊断

# 检查MD5是否一致
openssl x509 -noout -modulus -in cert.pem | openssl md5
openssl rsa -noout -modulus -in key.pem | openssl md5

解决:找到正确配对的私钥和证书。

坑3:证书过期

预防

# 写个脚本检查证书有效期
#!/bin/bash
DOMAIN=$1
EXPIRY=$(echo | openssl s_client -connect $DOMAIN:443 2>/dev/null | openssl x509 -noout -enddate | cut -d= -f2)
EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( ($EXPIRY_EPOCH - $NOW_EPOCH) / 86400 ))

echo "$DOMAIN 证书还有 $DAYS_LEFT 天过期"

if [ $DAYS_LEFT -lt 30 ]; then
    echo "⚠️ 警告:即将过期!"
fi

坑4:SNI问题

症状:同一IP部署多个HTTPS站点,访问时返回错误的证书。

原因:客户端不支持SNI,或者服务器SNI配置错误。

检查

# 指定SNI访问
openssl s_client -connect IP:443 -servername www.example.com

坑5:TLS版本过低

症状:旧浏览器能访问,新浏览器不行(或反过来)。

诊断

# 测试支持的TLS版本
for v in ssl3 tls1 tls1_1 tls1_2 tls1_3; do
    echo -n "$v: "
    timeout 2 openssl s_client -connect localhost:443 -$v 2>/dev/null | grep -q "Cipher" && echo "支持" || echo "不支持"
done

建议配置

# 只启用TLS 1.2和1.3(2024年的最佳实践)
ssl_protocols TLSv1.2 TLSv1.3;

常用命令速查表

场景命令
生成RSA私钥openssl genrsa -out key.pem 2048
生成自签名证书openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes
查看证书信息openssl x509 -in cert.pem -text -noout
查看证书有效期openssl x509 -in cert.pem -dates -noout
验证证书链openssl verify -CAfile ca.pem cert.pem
检查远程证书openssl s_client -connect host:443 -servername host
PEM转PFXopenssl pkcs12 -export -out cert.pfx -inkey key.pem -in cert.pem
PFX转PEMopenssl pkcs12 -in cert.pfx -out cert.pem -nodes
生成CSRopenssl req -new -key key.pem -out csr.pem
测试SSL服务器openssl s_server -cert cert.pem -key key.pem -port 4433
申请Let's Encryptcertbot certonly --standalone -d example.com
续期Let's Encryptcertbot renew

总结

OpenSSL知识图谱
│
├── 密钥管理
│   ├── RSA密钥对生成
│   ├── ECC密钥对生成
│   └── 密钥格式转换
│
├── 证书操作
│   ├── 自签名证书
│   ├── CSR生成
│   ├── 证书查看/验证
│   └── 格式转换(PEM/DER/PFX)
│
├── SSL/TLS测试
│   ├── s_server/s_client
│   ├── 远程证书检查
│   └── 性能测试
│
└── Let's Encrypt
    ├── Certbot安装
    ├── 多种验证方式
    ├── 自动续期
    └── Web服务器集成

从入门到放弃?不,是从入门到真香!

掌握OpenSSL,你就掌握了互联网安全的基础。虽然命令多、参数杂、格式乱,但一旦熟练了,你就是团队里那个"证书有问题找他准没错"的人。


参考资料


HTTP是在互联网上裸奔,HTTPS是穿了衣服。OpenSSL就是那个裁缝。 👔

无标签
评论区
暂无评论
avatar