一、方案背景与目标
1.1 现状
现有订单中心、支付中心、商品中心3个微服务应用,同属一个系统生态,目前各应用间通过HTTP协议相互调用,每个应用前置均部署独立Nginx代理,用于请求转发与基础防护。
1.2 痛点
HTTP协议为明文传输,存在数据窃听、篡改、伪造风险,尤其订单、支付等核心业务数据,传输过程中无加密保护,不符合内部安全规范。
1.3 目标
将微服务间调用统一切换为HTTPS加密协议,基于OpenSSL自签证书实现,补充单向认证、双向认证两种模式的完整配置;明确3种证书生成方案的细节与适用场景;提供Apache HttpClient客户端(忽略证书、信任证书)的完整改造方案;完成Nginx证书配置,确保改造无业务侵入、部署便捷。
二、证书生成方案
结合需求,明确3种证书生成方式的细节、优缺点及适用场景,重点提供企业级推荐方案的分步生成命令。
2.1 三种证书生成方案对比
| 生成方案 | 核心说明 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 方案1:所有应用共用1套证书 | 生成1套server.crt(服务端证书)、server.key(服务端私钥),订单、支付、商品中心共用该套证书 | 配置最简单、部署最快、无需管理多套证书,学习成本低 | 安全性差,1套证书泄露则所有微服务均受影响,无隔离性 | 内部测试环境、小规模微服务、对安全要求极低的场景 |
| 方案2:每个应用独立证书(无CA) | 订单、支付、商品中心分别生成独立的证书和私钥,互不关联,均为自签证书 | 隔离性好,单个应用证书泄露不影响其他应用,配置灵活 | 证书管理繁琐,客户端需分别信任每个应用的证书,运维成本高;例如订单中心需同时调用商品、支付中心时,需分别加载商品、支付中心的独立证书,配置和维护极为繁琐,易出现证书遗漏、配置错误问题 | 安全要求较高、服务数量较少(3-5个)的生产环境 |
| 方案3:CA根证书+签发各应用证书(推荐) | 先生成全局唯一的自签CA根证书,再用CA根证书分别签发订单、支付、商品中心的服务端证书,所有证书共用一个信任源 | 最安全、符合企业级规范;统一信任源,客户端只需信任CA根证书即可;便于证书吊销、统一管理 | 生成步骤稍多,需先创建CA根证书,再签发各应用证书 | 生产环境、核心微服务(订单、支付)、对安全要求高的场景(推荐首选) |
2.2 分步独立生成命令
全程分步执行,每一步均有明确说明,可单独复制执行,便于理解和排查问题;所有证书有效期默认10年(3650天),可根据需求调整。
第一步:环境准备(创建证书存放目录)
创建独立目录存放CA根证书和各应用证书,避免混淆,执行命令:
# 创建根证书目录(存放CA相关文件)
mkdir -p /usr/local/ssl/ssl_ca
# 创建各应用证书目录
mkdir -p /usr/local/ssl/ssl_order # 订单中心
mkdir -p /usr/local/ssl/ssl_pay # 支付中心
mkdir -p /usr/local/ssl/ssl_goods # 商品中心
# 进入CA根证书目录,开始生成CA
cd /usr/local/ssl/ssl_ca
第二步:生成CA根证书(全局唯一,信任锚点)
CA根证书用于签发所有微服务的服务端证书,客户端只需信任该CA,即可信任所有由其签发的证书,执行命令:
# 1. 生成CA根证书私钥(ca.key),2048位加密,无密码(便于管理,内网安全)
openssl genrsa -out ca.key 2048
# 2. 生成CA根证书公钥(ca.crt),自签名,有效期10年
# 执行后会提示输入国家、组织、域名等信息,可全部回车默认(内网使用无需严格填写)
openssl req -new -x509 -key ca.key -out ca.crt -days 3650
生成文件:ca.key(CA私钥,需妥善保管,不可泄露)、ca.crt(CA公钥,用于客户端信任和服务端签发)。
生成 CA 根证书时,无需填写任何微服务的独立域名(如order.micro-service.com、goods.micro-service.com),仅需填写 CA 自身的基础信息(可简单填写或默认);微服务的独立域名,只需要填在「生成各服务证书请求文件(.csr)的 Common Name 字段」中,对应你方案中订单、商品、支付中心的独立域名。
关键注意事项:
- 每个微服务的 Common Name,必须和它 Nginx 配置中的 server_name 完全一致(比如订单中心 Nginx 配置 server_name order.micro-service.com,csr 中就必须填这个域名),否则客户端会报 “证书域名不匹配” 错误。
- CA 根证书的 Common Name,无需和任何微服务域名一致,只要是自定义的 CA 名称即可(比如 MicroService-CA)。
- 除了 Common Name,其他字段(国家、组织等)可与 CA 根证书保持一致,也可留空,不影响证书的签发和校验(内网场景无需严格填写)。
第三步:用CA签发订单中心证书
进入订单中心证书目录,生成私钥、证书请求文件,再用CA根证书签发,执行命令:
# 进入订单中心证书目录
cd /usr/local/ssl/ssl_order
# 1. 生成订单中心服务端私钥(order.key)
openssl genrsa -out order.key 2048
# 2. 生成证书请求文件(order.csr),用于向CA申请签发证书
# 提示信息可回车默认,与CA根证书信息一致即可
openssl req -new -key order.key -out order.csr
# 3. 用CA根证书签发订单中心服务端证书(order.crt),有效期10年
openssl x509 -req -in order.csr -CA /usr/local/ssl/ssl_ca/ca.crt -CAkey /usr/local/ssl/ssl_ca/ca.key -CAcreateserial -out order.crt -days 3650
生成文件:order.key(订单服务私钥)、order.csr(证书请求文件,可删除)、order.crt(订单服务证书)。
第四步:用CA签发支付中心证书
与订单中心步骤一致,替换对应文件名,执行命令:
# 进入支付中心证书目录
cd /usr/local/ssl/ssl_pay
# 1. 生成支付中心服务端私钥(pay.key)
openssl genrsa -out pay.key 2048
# 2. 生成证书请求文件(pay.csr)
openssl req -new -key pay.key -out pay.csr
# 3. 用CA根证书签发支付中心服务端证书(pay.crt)
openssl x509 -req -in pay.csr -CA /usr/local/ssl/ssl_ca/ca.crt -CAkey /usr/local/ssl/ssl_ca/ca.key -CAcreateserial -out pay.crt -days 3650
第五步:用CA签发商品中心证书
同理,执行命令:
# 进入商品中心证书目录
cd /usr/local/ssl/ssl_goods
# 1. 生成商品中心服务端私钥(goods.key)
openssl genrsa -out goods.key 2048
# 2. 生成证书请求文件(goods.csr)
openssl req -new -key goods.key -out goods.csr
# 3. 用CA根证书签发商品中心服务端证书(goods.crt)
openssl x509 -req -in goods.csr -CA /usr/local/ssl/ssl_ca/ca.crt -CAkey /usr/local/ssl/ssl_ca/ca.key -CAcreateserial -out goods.crt -days 3650
补充:方案1、方案2的简化生成命令
若使用方案1(共用1套证书),只需生成1套证书,复制到所有应用目录即可:
# 生成共用证书(以server为前缀)
mkdir -p /usr/local/ssl/ssl_common
cd /usr/local/ssl/ssl_common
openssl genrsa -out server.key 2048
openssl req -new -x509 -key server.key -out server.crt -days 3650
若使用方案2(各应用独立证书,无CA),只需省略“CA签发”步骤,直接生成自签证书:
# 以订单中心为例,其他应用同理
cd /usr/local/ssl/ssl_order
openssl genrsa -out order.key 2048
openssl req -new -x509 -key order.key -out order.crt -days 3650
三、HTTPS单向认证与双向认证配置
基于方案3(CA+各应用证书),补充单向认证、双向认证的完整Nginx配置,适配不同安全需求;单向认证仅客户端验证服务端,双向认证双方互验,核心微服务推荐双向认证。
3.1 单向认证配置
核心逻辑:仅客户端验证服务端证书的合法性,服务端不验证客户端身份,配置简单、性能损耗低,适用于非核心微服务(如商品中心查询接口)。
以订单中心Nginx为例,支付、商品中心同理,替换对应证书路径和服务地址:
server {
listen 443 ssl; # 监听HTTPS默认端口443
server_name order.micro-service.com; # 订单中心内网域名(需与证书一致)
# 服务端证书配置(方案3生成的订单中心证书)
ssl_certificate /usr/local/ssl/ssl_order/order.crt; # 服务端证书
ssl_certificate_key /usr/local/ssl/ssl_order/order.key; # 服务端私钥
# SSL安全优化(固定配置,提升安全性)
ssl_protocols TLSv1.2 TLSv1.3; # 禁用低版本TLS,提升安全
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5; # 加密套件
ssl_prefer_server_ciphers on; # 优先使用服务端加密套件
# 代理转发到后端订单中心微服务(HTTP不变,Nginx负责HTTPS解密)
location / {
proxy_pass http://127.0.0.1:8080; # 订单中心微服务本地端口
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr; # 传递客户端真实IP
}
}
# 强制HTTP跳转HTTPS(可选,避免HTTP访问)
server {
listen 80;
server_name order.micro-service.com;
return 301 https://$host$request_uri; # 所有HTTP请求跳转至HTTPS
}
3.2 双向认证配置
核心逻辑:客户端验证服务端证书 + 服务端验证客户端证书,安全性最高,可杜绝非法客户端调用,适用于订单中心、支付中心等核心微服务。
在单向认证基础上,增加“客户端证书校验”配置,以支付中心Nginx为例:
server {
listen 443 ssl;
server_name pay.micro-service.com; # 支付中心内网域名
# 服务端证书配置(方案3生成的支付中心证书)
ssl_certificate /usr/local/ssl/ssl_pay/pay.crt;
ssl_certificate_key /usr/local/ssl/ssl_pay/pay.key;
# 双向认证核心配置(新增)
ssl_client_certificate /usr/local/ssl/ssl_ca/ca.crt; # 信任的CA根证书(用于验证客户端证书)
ssl_verify_client on; # 开启客户端证书校验(强制校验)
ssl_verify_depth 2; # 校验深度,默认2即可
# SSL安全优化(与单向认证一致)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# 代理转发到后端支付中心微服务
location / {
proxy_pass http://127.0.0.1:8081; # 支付中心微服务本地端口
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
# 强制HTTP跳转HTTPS
server {
listen 80;
server_name pay.micro-service.com;
return 301 https://$host$request_uri;
}
补充说明:双向认证需客户端携带CA签发的客户端证书(后续客户端改造会补充),服务端通过CA根证书验证客户端证书的合法性,非法客户端无法建立连接。
四、客户端改造(Apache HttpClient,忽略/信任证书)
微服务作为调用方(客户端),需改造HTTP调用逻辑,切换为HTTPS,并配置证书校验方式(忽略证书/信任证书);服务端无需改造代码,由Nginx负责HTTPS加密/解密。
以下均基于Apache HttpClient(用户指定)实现,提供完整可直接使用的工具类,适配单向认证、双向认证场景。
4.1 依赖准备(Maven)
确保项目引入Apache HttpClient依赖,版本推荐4.5+:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.14</version>
</dependency>
4.2 方案1:忽略证书(不安全,仅测试用)
核心逻辑:关闭SSL证书校验,跳过服务端证书合法性验证,适用于测试环境(避免频繁处理证书信任问题),生产环境严禁使用。
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.cert.X509Certificate;
/**
* Apache HttpClient 忽略证书工具类(测试用)
*/
public class HttpsIgnoreCertUtil {
/**
* 获取忽略证书的HttpClient实例
*/
public static CloseableHttpClient getIgnoreSslHttpClient() throws Exception {
// 1. 创建信任管理器:不校验任何证书
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
// 不校验客户端证书
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) {}
// 不校验服务端证书
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {}
// 无需返回可信任证书
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
};
// 2. 初始化SSL上下文,关闭证书校验
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
// 3. 创建SSL连接工厂,忽略主机名校验(避免域名与证书不一致报错)
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(
sslContext,
NoopHostnameVerifier.INSTANCE // 忽略主机名校验
);
// 4. 构建HttpClient实例,设置SSL连接工厂
return HttpClients.custom()
.setSSLSocketFactory(sslSocketFactory)
.build();
}
/**
* 测试调用示例(GET请求)
*/
public static void main(String[] args) throws Exception {
CloseableHttpClient httpClient = getIgnoreSslHttpClient();
// 调用地址改为HTTPS(订单中心示例)
String url = "https://order.micro-service.com/api/order/list";
// 后续执行GET/POST请求,与HTTP调用逻辑一致
// ...(省略请求执行代码,与普通HttpClient调用相同)
}
}
忽略证书具体忽略的信息是什么?
忽略证书本质是关闭客户端对服务端证书的所有合法性校验,具体忽略以下关键信息,无论这些信息是否异常,均会允许建立HTTPS连接:
- 证书有效期:忽略证书是否过期(已过有效期)、是否未生效(未到起始有效期),即使证书过期仍可正常连接。
- 证书域名匹配:忽略证书中绑定的域名(或IP)与实际访问的服务域名(或IP)是否一致,比如证书绑定order.micro-service.com,访问pay.micro-service.com也可正常连接。
- 证书签发机构合法性:忽略证书是否由可信CA机构签发(自签证书、非法机构签发的证书均会被信任),无需验证签发机构的有效性。
- 证书完整性与合法性:忽略证书是否被篡改、是否存在伪造、是否符合SSL证书格式规范,即使证书被篡改也会正常建立连接。
- 证书吊销状态:忽略证书是否已被签发机构吊销(即使证书已吊销,仍可正常使用)。
4.3 方案2:信任自签CA证书
核心逻辑:客户端仅信任我们自己生成的CA根证书(方案3中的ca.crt),既保证安全,又避免频繁校验,适配单向认证、双向认证场景。
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
/**
* Apache HttpClient 信任CA证书工具类(生产用)
*/
public class HttpsTrustCaUtil {
// CA根证书路径(根据实际部署路径修改)
private static final String CA_CERT_PATH = "/usr/local/ssl/ssl_ca/ca.crt";
/**
* 获取信任CA证书的HttpClient实例(单向认证可用)
*/
public static CloseableHttpClient getTrustCaHttpClient() throws Exception {
// 1. 加载CA根证书
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
FileInputStream caInputStream = new FileInputStream(CA_CERT_PATH);
X509Certificate caCert = (X509Certificate) certificateFactory.generateCertificate(caInputStream);
caInputStream.close();
// 2. 创建KeyStore,将CA根证书存入(作为信任锚点)
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null); // 初始化空的KeyStore
keyStore.setCertificateEntry("micro-service-ca", caCert); // 存入CA证书
// 3. 初始化信任管理器工厂,指定信任的KeyStore
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm()
);
trustManagerFactory.init(keyStore);
// 4. 初始化SSL上下文,仅信任指定CA
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagerFactory.getTrustManagers(), new java.security.SecureRandom());
// 5. 创建SSL连接工厂,验证主机名(生产环境建议开启)
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext);
// 6. 构建HttpClient实例
return HttpClients.custom()
.setSSLSocketFactory(sslSocketFactory)
.build();
}
/**
* 获取信任CA+携带客户端证书的HttpClient实例(双向认证可用)
* 双向认证需额外加载客户端证书(由CA签发)
*/
public static CloseableHttpClient getTrustCaWithClientCertHttpClient() throws Exception {
// 1. 加载CA根证书(与单向认证一致)
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
FileInputStream caInputStream = new FileInputStream(CA_CERT_PATH);
X509Certificate caCert = (X509Certificate) certificateFactory.generateCertificate(caInputStream);
caInputStream.close();
// 2. 加载客户端证书(客户端私钥+客户端证书,由CA签发)
String clientKeyPath = "/usr/local/ssl/client/client.key"; // 客户端私钥
String clientCertPath = "/usr/local/ssl/client/client.crt";// 客户端证书
KeyStore clientKeyStore = KeyStore.getInstance("PKCS12");
// 加载客户端证书和私钥(若私钥有密码,需传入密码,此处无密码)
clientKeyStore.load(new FileInputStream(clientCertPath), null);
clientKeyStore.setKeyEntry("client-key", new FileInputStream(clientKeyPath), null, new X509Certificate[]{caCert});
// 3. 初始化信任管理器(信任CA)和密钥管理器(加载客户端证书)
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm()
);
trustManagerFactory.init(KeyStore.getInstance(KeyStore.getDefaultType()));
// 4. 初始化SSL上下文,同时设置信任管理器和密钥管理器
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(
null, // 密钥管理器(若客户端私钥有密码,需传入)
trustManagerFactory.getTrustManagers(),
new java.security.SecureRandom()
);
// 5. 创建SSL连接工厂
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext);
// 6. 构建HttpClient实例
return HttpClients.custom()
.setSSLSocketFactory(sslSocketFactory)
.build();
}
/**
* 生产环境调用示例(POST请求)
*/
public static void main(String[] args) throws Exception {
// 单向认证调用(如调用商品中心)
CloseableHttpClient httpClient = getTrustCaHttpClient();
// 双向认证调用(如调用支付中心)
// CloseableHttpClient httpClient = getTrustCaWithClientCertHttpClient();
// 调用地址改为HTTPS(支付中心示例)
String url = "https://pay.micro-service.com/api/pay/create";
// 后续执行POST请求,传递参数,与HTTP调用逻辑一致
// ...(省略请求执行代码)
}
}
4.4 客户端改造核心步骤
- 将微服务中所有调用地址,从
http://改为https://(如订单中心调用支付中心,从pay.micro-service.com改为pay.micro-service.com)。 - 注入上述工具类中的HttpClient实例,替换原有HTTP调用的客户端(如RestTemplate底层使用该HttpClient)。
- 单向认证:使用
getTrustCaHttpClient()方法,仅信任CA根证书即可。 - 双向认证:使用
getTrustCaWithClientCertHttpClient()方法,需额外准备客户端证书(由CA签发,生成命令可补充)。 - 无需修改业务逻辑,仅改造HTTP调用的客户端配置,实现无侵入改造。
4.5 PC客户端(浏览器)改造说明
PC端客户端核心以浏览器(Chrome、Edge、Firefox等)为主,其证书加载逻辑与Java微服务客户端不同,核心取决于认证模式(单向/双向),且支持“无需加载证书”的场景,具体如下:
4.5.1 单向认证场景(PC浏览器)
单向认证仅要求浏览器验证服务端证书合法性,可无需手动加载证书,因使用自签CA证书,浏览器会提示“证书不受信任”,两种便捷处理方式:
- 临时访问(测试环境首选):访问HTTPS地址时,弹出“连接非私密”提示,点击“高级”→“继续访问”,即可正常访问,无需加载任何证书。
- 永久信任(生产环境首选):将CA根证书(ca.crt)导入浏览器“受信任的根证书颁发机构”,导入后浏览器默认信任所有该CA签发的服务端证书,无警告提示(主流浏览器操作逻辑一致,核心是导入CA根证书)。
关键说明:单向认证场景下,PC浏览器无需强制加载证书,临时信任可满足测试需求,生产环境导入CA根证书更规范。
4.5.2 双向认证场景(PC浏览器)
双向认证要求浏览器(客户端)同时验证服务端证书、服务端验证浏览器(客户端)证书,因此必须加载客户端证书,步骤如下:
- 先将CA根证书(ca.crt)导入浏览器(步骤同单向认证永久信任),确保浏览器信任服务端证书;
- 将客户端证书(client.crt)导入浏览器(以Chrome为例):进入“管理证书”→“个人”选项卡→“导入”,选择client.crt文件,完成导入;
- 访问双向认证的HTTPS地址时,浏览器会自动弹出“选择证书”提示,选择导入的客户端证书,即可完成身份校验,正常访问。
补充:若客户端证书为PKCS12格式(.p12/.pfx),导入方式一致,导入时需输入证书密码(若设置);未加载客户端证书时,浏览器会提示“400 Bad Request”或“SSL握手失败”。
4.6 APP客户端改造说明
APP客户端(Android、iOS)改造核心是处理自签CA证书的信任问题,适配单向/双向认证,无需用户手动加载证书(由开发人员在APP内集成),具体如下:
4.6.1 单向认证场景(APP)
核心逻辑:APP内集成CA根证书,信任服务端证书,无需用户操作,开发端改造步骤:
-
Android端:将ca.crt证书放入APP项目的assets目录,在网络请求框架(如OkHttp)中配置SSL上下文,加载CA根证书,信任该证书对应的服务端,示例代码(OkHttp):
// 加载CA根证书 InputStream caInput = getAssets().open("ca.crt"); CertificateFactory cf = CertificateFactory.getInstance("X.509"); X509Certificate caCert = (X509Certificate) cf.generateCertificate(caInput); caInput.close(); // 配置信任管理器 KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); keyStore.load(null); keyStore.setCertificateEntry("ca", caCert); TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(keyStore); // 配置OkHttp信任该CA SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, tmf.getTrustManagers(), new SecureRandom()); OkHttpClient client = new OkHttpClient.Builder() .sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) tmf.getTrustManagers()[0]) .build(); ```iOS端:将ca.crt证书导入项目,在Info.plist中配置证书信任,使用NSURLSession请求时,通过SSL证书校验逻辑,信任该CA签发的服务端证书,避免系统提示“证书不受信任”。
4.6.2 双向认证场景(APP)
核心逻辑:APP内同时集成CA根证书(信任服务端)和客户端证书(用于服务端校验),无需用户手动加载,开发端改造步骤:
- Android端:在单向认证改造基础上,额外加载客户端证书(client.crt)和客户端私钥(client.key),配置SSL上下文时同时设置信任管理器和密钥管理器,实现双向认证。
- iOS端:将客户端证书(.p12格式,便于iOS集成)导入项目,在网络请求时,指定客户端证书用于身份校验,与服务端完成双向SSL握手。
关键说明:APP客户端证书均由开发人员集成到安装包中,用户无需手动操作;双向认证场景下,客户端证书需妥善保管,避免打包泄露。
4.7 多客户端改造总结
| 客户端类型 | 单向认证(是否需加载证书) | 双向认证(是否需加载证书) | 核心注意点 |
|---|---|---|---|
| Java微服务 | 需加载CA根证书(或忽略证书) | 需加载CA根证书+客户端证书 | 使用Apache HttpClient配置SSL上下文 |
| PC浏览器 | 可不用加载(临时信任),推荐加载CA根证书 | 必须加载CA根证书+客户端证书 | 导入证书到浏览器对应证书库 |
| APP客户端(Android/iOS) | 无需用户加载,开发端集成CA根证书 | 无需用户加载,开发端集成CA根证书+客户端证书 | 证书集成到安装包,避免泄露 |
4.8 关键疑问解答
4.8.1 忽略证书、信任证书(加载证书)与单向认证、双向认证的关系
忽略证书、信任证书(加载证书)是客户端的证书校验方式,单向认证、双向认证是HTTPS的认证模式,二者相互配合,无直接绑定关系,但有固定适配场景,核心关系如下:
- 忽略证书(客户端):可适配单向认证、双向认证两种模式,但仅用于测试环境,生产环境严禁使用。
- 适配单向认证:客户端忽略服务端证书校验,服务端不校验客户端,可正常建立连接(测试用)。
- 适配双向认证:客户端忽略服务端证书校验,同时携带客户端证书供服务端校验,服务端校验客户端证书通过后,可建立连接(仅测试用,失去双向认证的安全意义)。
- 信任证书(加载证书,客户端):是生产环境的标准配置,可适配单向认证、双向认证两种模式,核心是客户端仅信任指定证书(CA根证书/客户端证书)。
- 适配单向认证:客户端加载并信任服务端证书(或CA根证书),验证服务端合法性;服务端不校验客户端,这是生产环境单向认证的标准配置。
- 适配双向认证:客户端同时加载并信任CA根证书(验证服务端)、加载客户端证书(供服务端校验);服务端加载CA根证书(验证客户端),这是生产环境双向认证的标准配置。
核心区别:单/双向认证决定“双方是否互验身份”,忽略/信任证书决定“客户端如何验证服务端身份”,二者独立但需配合使用(生产环境需“信任证书+对应认证模式”)。
4.8.2 是不是只要有证书了,最低都是单向认证?
是的,只要服务端配置了HTTPS证书(无论哪种生成方案),最低都是单向认证,核心原因如下:
- HTTPS的基础逻辑:HTTPS本质是“HTTP+SSL/TLS加密”,而SSL/TLS握手的核心第一步就是“客户端验证服务端证书”,这是HTTPS的默认行为,也是单向认证的核心逻辑。
- 单向认证的本质:仅客户端验证服务端证书(确认服务端身份合法),服务端不验证客户端,这是HTTPS的最低安全门槛——只要启用HTTPS(配置证书),就会触发客户端对服务端的证书校验,即默认开启单向认证。
- 特殊说明:客户端“忽略证书”,并不是关闭单向认证,而是跳过了“客户端对服务端证书的校验”,但服务端仍处于“单向认证模式”(不校验客户端);双向认证是在单向认证的基础上,增加了“服务端对客户端的证书校验”,是更高安全级别的认证模式。
总结:HTTPS(配置证书)= 单向认证(默认),双向认证是单向认证的升级版本,需额外配置客户端证书校验。
五、部署与验证步骤
5.1 部署步骤
- 证书部署:将CA根证书、各应用证书(key和crt文件)拷贝到对应Nginx的证书目录(如/usr/local/ssl/对应目录),确保权限为600(仅管理员可读写)。
- Nginx配置:替换各应用的Nginx配置文件(按单向/双向认证配置),检查证书路径是否正确。
- 重启Nginx:执行
nginx -t检查配置语法,无错误后执行nginx -s reload重启。 - 客户端改造:微服务集成上述HttpClient工具类,修改调用地址为HTTPS,部署微服务。
5.2 验证命令
# 1. 单向认证验证(调用订单中心,仅信任CA)
curl -v --cacert /usr/local/ssl/ssl_ca/ca.crt https://order.micro-service.com/api/order/list
# 2. 双向认证验证(调用支付中心,需携带客户端证书)
curl -v --cacert /usr/local/ssl/ssl_ca/ca.crt --cert /usr/local/ssl/client/client.crt --key /usr/local/ssl/client/client.key https://pay.micro-service.com/api/pay/create
# 3. 忽略证书验证(测试用,快速排查服务是否可用)
curl -v -k https://order.micro-service.com/api/order/list
验证成功:返回200状态码,获取正常响应;验证失败:检查证书路径、Nginx配置、客户端证书是否正确。
六、注意事项与方案总结
6.1 注意事项
- 证书安全:CA私钥(ca.key)需妥善保管,不可泄露;服务端/客户端私钥建议设置密码(生成命令可添加
-aes256 -passout pass:密码),增强安全性。 - 环境适配:测试环境可使用“忽略证书”或“共用证书”,生产环境必须使用“CA+各应用证书”+双向认证(核心服务)。
- 版本兼容:Apache HttpClient版本建议4.5+,避免低版本不支持TLS1.2/1.3,导致连接失败。
- 主机名校验:生产环境不建议关闭主机名校验(NoopHostnameVerifier),确保证书域名与服务域名一致。
- 证书更新:证书有效期为10年,到期前需重新用CA签发,避免证书过期导致服务不可用。
6.2 方案总结
- 证书方案:优先选择“CA根证书+各应用证书”(方案3),兼顾安全性和可管理性;测试环境可简化为“共用证书”(方案1)。
- 认证模式:核心微服务(订单、支付)用双向认证,非核心服务(商品)用单向认证,平衡安全与性能。
- 改造范围:服务端仅配置Nginx,无需修改微服务代码;客户端仅改造HTTP调用客户端,无业务侵入。
- 客户端选择:测试用“忽略证书”,生产用“信任证书”,双向认证需额外加载客户端证书。
- 优势:基于OpenSSL自签证书,零成本、内网可控,适配现有微服务架构,安全性满足内部业务需求。
七、补充技术知识点(证书相关)
本章节补充HTTPS证书相关核心技术知识点,明确各类证书文件、关键参数的作用,以及CA根证书签发证书的本质,帮助理解证书生成与校验的底层逻辑。
7.1 Nginx配置crt证书后的客户端交互逻辑
当Nginx配置了ssl_certificate(即.crt文件)后,在SSL/TLS握手阶段,Nginx会自动将该证书发送给客户端。客户端收到证书后,有两种处理策略,其专业术语如下:
-
交互流程:
- 证书传递:客户端发起HTTPS连接 -> Nginx响应并发送其配置的
.crt证书(包含公钥)。 - 客户端校验:客户端根据自身配置,决定如何处理该证书。
- 证书传递:客户端发起HTTPS连接 -> Nginx响应并发送其配置的
-
两种校验方式的专业术语:
-
跳过校验(Trust Any/Insecure Skip Verify) :
- 术语:证书信任跳过(Certificate Trust Bypass) 或 不安全跳过(Insecure Skip Verify) 。
- 逻辑:客户端不验证Nginx发送的证书是否合法、是否过期、域名是否匹配,直接建立加密连接。对应代码中的
TrustManager不做任何检查。 - 场景:仅限测试环境(如前文的
HttpsIgnoreCertUtil)。
-
合法性校验(Certificate Chain Validation) :
- 术语:证书链校验(Certificate Chain Validation) 。
- 逻辑:客户端加载可信的CA根证书(如前文的
ca.crt),使用该CA证书去验证Nginx发送的证书是否由该CA签发、是否在有效期内、域名是否匹配。 - 场景:生产环境标准配置(如前文的
HttpsTrustCaUtil)。
-
7.2 核心证书文件(key、csr、crt)与参数详解
在证书生成过程中,key、csr、crt是三个核心文件,配合X.509等标准共同工作。
1. 三种核心文件的作用
| 文件后缀 | 全称 | 中文含义 | 核心作用与保管要求 |
|---|---|---|---|
| .key | Private Key | 私钥文件 | 核心机密。用于加密解密和数字签名。必须严格保管,不可泄露。泄露意味着证书被伪造。服务端配置时需确保文件权限为600。 |
| .csr | Certificate Signing Request | 证书请求文件 | 申请书。包含申请者的公钥和身份信息(如域名、组织)。用于向CA机构(或自建CA)申请签发正式证书。签发完成后,该文件通常不再需要,可删除。 |
| .crt | Certificate | 证书文件 | 身份证。由CA签发,包含公钥、持有者信息、有效期、CA签名等。用于分发给客户端(用于信任)或配置在服务端(用于出示身份)。 |
2. 关键参数与标准:X.509
-
X.509:
- 定义:这是国际电信联盟(ITU)和国际标准化组织(ISO)制定的数字证书标准。
- 作用:它定义了公钥证书的格式,规定了证书中必须包含的信息(如版本号、序列号、签名算法、颁发者、有效期、主体、公钥信息、扩展信息等)。
- 现状:目前互联网上绝大多数SSL/TLS证书都遵循X.509标准(通常是v3版本)。我们在OpenSSL命令中使用的
-x509参数,就是指生成一个自签的X.509格式证书。
3. CA根证书签发证书的本质与作用
-
本质: CA根证书签发子证书的本质是 “数字签名”(Digital Signing) 的过程。 CA机构(或我们自建的CA)使用自己的私钥(ca.key) ,对服务端提交的证书请求(server.csr) 中的信息(公钥、域名等)进行加密哈希运算,生成一个签名(Signature) ,并将这个签名和CA的信息打包,生成最终的服务端证书(server.crt) 。最终的 server.crt(对应你方案中的 order.crt、pay.crt 等),既包含服务端本身的公钥及服务端信息,也包含 CA 的公钥及 CA 的信息
-
作用(为什么需要CA签发?) :
- 建立信任链(Chain of Trust) : 客户端只需要信任根证书(Root CA),就可以信任所有由该根证书直接或间接签发的下级证书。这解决了“公钥分发”的信任问题。
- 防篡改(Integrity) : 如果攻击者篡改了服务端证书中的任何信息(比如把公钥换了),客户端用CA的公钥去验证签名时就会失败,从而发现证书被篡改。
- 统一管理(Scalability) : 在微服务架构中,如果有100个服务,客户端不需要维护100个服务的公钥。客户端只需维护1个CA根证书,即可验证这100个服务的身份。这就是前文推荐“方案3(CA+各应用证书)”的核心优势。
4. CA根证书签发证书的本质与作用
因为CRT是CA签发之后才产生的结果,你不能对“结果”进行“签发”,你只能对“申请”进行“签发”。简单来说:CSR是“申请书”,CRT是“身份证”。CA机构的工作是“审批申请”并“颁发身份证”,而不是拿着一张已经做好的身份证去盖章。 CSR里包含了公钥,CA需要把公钥写进证书里。
CA到底对什么进行了“签名”?
- 提取信息:CA解析CSR文件,提取出里面的
主体信息(比如CN=www.example.com)和公钥。 - 组装结构:CA把这些信息,加上
有效期、序列号、颁发者信息,组装成一个符合 X.509标准 的数据结构(这叫TBS证书,即“待签名证书”)。 - 数字签名:CA使用自己的 CA私钥,对这个TBS数据进行哈希运算并加密,生成 签名值。
- 生成CRT:CA把
TBS数据+签名值拼在一起,保存为.crt文件。
7.3 HTTPS认证加密完整流程
HTTPS核心是「先认证身份,再加密传输」,全程依赖你生成的各类证书,流程如下(以订单中心单向认证、支付中心双向认证为例):
1. 建立连接(触发SSL/TLS握手)
客户端(如商品中心微服务、浏览器)发起HTTPS请求(如order.micro-service.com),首先与服务端Nginx建立TCP连接,随后触发SSL/TLS握手(这是认证和加密的核心环节,对应你文档3.1中的补充说明)。
2. 身份认证(核心步骤,证书发挥关键作用)
这一步分「单向认证」和「双向认证」,对应你方案中的两种配置,证书作用完全不同:
- 单向认证(如商品中心调用订单中心): ① 服务端(Nginx)自动发送自身证书(order.crt,服务端证书)给客户端; ② 客户端(商品中心微服务)通过加载的CA根证书(ca.crt),校验order.crt的合法性(确认是由可信的CA签发、未被篡改)—— 这就是你文档中说的「证书链校验」; ③ 校验通过,确认服务端是合法的订单中心(不是伪造的);校验失败,拒绝建立连接。
- 双向认证(如订单中心调用支付中心): ① 先执行单向认证的所有步骤(服务端发送pay.crt,客户端用ca.crt校验); ② 服务端(Nginx)要求客户端出示身份凭证(客户端证书client.crt); ③ 客户端发送client.crt给服务端,服务端通过自身配置的CA根证书(ca.crt),校验client.crt的合法性; ④ 双方身份都验证通过,进入下一步;任意一方校验失败,连接终止。
3. 协商加密算法与会话密钥
身份认证通过后,客户端和服务端会协商一套「对称加密算法」(如AES),并生成一个「临时会话密钥」(用于后续数据加密)。
- 关键:这个会话密钥的传递的是「加密的」—— 用服务端证书(order.crt/pay.crt)的公钥加密会话密钥,只有服务端的私钥(order.key/pay.key)能解密,避免会话密钥被窃听。
4. 加密传输数据
后续客户端与服务端的所有交互(如查询订单、发起支付),都会用步骤3协商好的「会话密钥」进行对称加密,传输的数据都是密文,即使被截取,也无法破解(除非会话密钥泄露)。
- 补充:对称加密效率高,适合大量数据传输;而证书的公钥/私钥加密(非对称加密),仅用于「身份认证」和「会话密钥传递」(非对称加密效率低,不适合大量数据传输)。
7.4 各类证书文件在流程中的核心作用
结合你生成的证书(ca.crt、ca.key、order.crt、order.key、client.crt等),逐个说明作用,对应流程中的具体环节:
1. CA根证书相关(ca.crt、ca.key)
- ca.crt(CA根证书公钥):「信任锚点」,所有校验的核心依据。 ① 客户端用它校验服务端证书(order.crt/pay.crt)的合法性(确认是自己签发的,未被篡改); ② 服务端(双向认证)用它校验客户端证书(client.crt)的合法性; ③ 对应你方案的核心优势:只需信任1个ca.crt,无需逐个信任每个服务的证书,简化配置。
- ca.key(CA根证书私钥):「签发证书的核心钥匙」,仅用于签发服务端/客户端证书(如order.crt、client.crt),不可泄露(一旦泄露,攻击者可伪造任意证书,整个认证体系失效)。
2. 服务端证书相关(order.crt、order.key、pay.crt、pay.key等)
- 服务端证书(order.crt/pay.crt):「服务端的身份凭证」,相当于服务端的“身份证”。 ① 单向/双向认证中,传递给客户端,证明自己是合法的服务端; ② 包含服务端的公钥,用于加密「会话密钥」,传递给服务端。
- 服务端私钥(order.key/pay.key):「服务端的专属钥匙」,仅存于服务端Nginx,不可泄露。 ① 解密客户端用服务端证书公钥加密的「会话密钥」; ② 验证自身证书的合法性(防止证书被篡改)。
3. 客户端证书相关(client.crt、client.key)
- client.crt(客户端证书):「客户端的身份凭证」,仅用于双向认证。 ① 双向认证中,客户端传递给服务端,证明自己是合法的调用方(如订单中心调用支付中心,需出示client.crt); ② 由CA根证书(ca.crt)签发,确保服务端能通过ca.crt校验其合法性。
- client.key(客户端私钥):「客户端的专属钥匙」,仅存于客户端(如订单中心微服务),不可泄露。 ① 配合client.crt,完成服务端对客户端的身份校验; ② 部分场景下,用于解密服务端发送的加密数据(按需配置)。
总结:
- 认证流程:先握手 → 身份认证(单/双向,证书核心作用) → 协商密钥 → 加密传输;
- 证书核心:ca.crt是“信任核心”,服务端证书是“服务端身份证”,客户端证书是“客户端身份证”,私钥(ca.key、order.key等)是“解密/签发的专属钥匙”;
- 对应你方案:你生成的3种证书方案,本质是改变“身份认证的凭证来源”,但HTTPS的认证加密流程不变,只是证书的使用方式不同(如方案1共用证书,就是所有服务共用1个“身份证”)。
7.5单证书多域名场景
7.5.1 一个证书能填多个域名吗?
可以,(用SAN字段)。默认情况下,你之前执行的 openssl req -new -key order.key -out order.csr 命令,仅能在 Common Name 字段填写1个域名(如order.micro-service.com),无法直接填多个域名。
但可以通过 添加SAN(Subject Alternative Name,主题备用名称)字段,让一个证书绑定多个独立域名(如同时绑定order.micro-service.com、goods.micro-service.com),适配你多微服务共用1个证书的场景(方案1可优化)。
具体操作(适配你方案的OpenSSL命令):
-
新建一个配置文件(如san.cnf),添加SAN字段,内容如下(可直接复制):
[req] distinguished_name = req_distinguished_name req_extensions = v3_req [req_distinguished_name] CN = order.micro-service.com # 主域名(可任意填,最终以SAN为准) [v3_req] keyUsage = digitalSignature, keyEncipherment extendedKeyUsage = serverAuth subjectAltName = @alt_names [alt_names] DNS.1 = order.micro-service.com # 订单中心域名 DNS.2 = goods.micro-service.com # 商品中心域名 DNS.3 = pay.micro-service.com # 支付中心域名 # 可继续添加更多域名,DNS.4、DNS.5... -
生成csr文件时,指定该配置文件,命令修改为:
openssl req -new -key order.key -out order.csr -config san.cnf -
后续用CA根证书签发crt证书(命令不变),生成的order.crt即可同时绑定3个微服务域名,Nginx配置时只需用这1个证书,所有绑定域名均可正常通过HTTPS校验。
注意事项:
- 适配场景:适合方案1(共用1套证书),可减少证书管理成本,无需为每个微服务单独生成证书;
- 校验要求:证书绑定的所有域名,需与Nginx配置的
server_name完全一致(如证书绑定goods.micro-service.com,Nginx的server_name也需填这个); - 兼容性:主流浏览器、微服务客户端(Apache HttpClient)均支持SAN字段,无兼容性问题。
7.5.2 域名能用通配符吗?
可以使用通配符域名(如*.micro-service.com),一个证书可匹配所有以micro-service.com为后缀的子域名,完美适配你所有微服务(订单、商品、支付均为子域名)的场景,比SAN字段更简洁。
具体操作(适配你方案的OpenSSL命令):
-
无需新建配置文件,直接生成csr时,在
Common Name字段填写通配符域名即可:- 执行命令
openssl req -new -key server.key -out server.csr; - 当提示
Common Name []:时,填写*.micro-service.com(仅填这一个,无需其他域名);
- 执行命令
-
用CA根证书签发crt证书(命令不变),生成的server.crt可匹配所有子域名:
- 适配:order.micro-service.com、goods.micro-service.com、pay.micro-service.com 均能正常使用该证书;
-
Nginx配置:所有微服务的Nginx,均可使用这套证书,
server_name填写对应子域名即可(如order.micro-service.com)。
注意事项(必看,避免踩坑):
- 通配符范围:仅匹配一级子域名,比如
*.micro-service.com可匹配order.micro-service.com,但无法匹配a.order.micro-service.com(二级子域名); - 场景适配:比SAN字段更适合你当前的微服务架构(所有服务均为同一后缀子域名),方案1(共用证书)用通配符证书最便捷;
- 安全性:与普通证书一致,仅需妥善保管私钥,适合测试环境或非核心服务;核心服务(支付中心)建议用独立证书(方案3),更安全。
总结
-
多域名需求:用SAN字段(可绑定任意多个不同后缀域名)或通配符(仅绑定同一后缀子域名),均可实现“一个证书多个域名”;
-
你的场景推荐:优先用 通配符域名(*.micro-service.com) ,操作更简单,无需配置SAN文件,适配所有微服务子域名;
-
与方案适配:
- 方案1(共用证书):用通配符证书,大幅简化配置和管理;
- 方案3(CA+各应用证书):不推荐用多域名/通配符,建议每个微服务用独立证书(隔离性好,更安全)。
7.5.2 证书过期了怎么办?
一、核心原则(必遵循)
- 过期证书无法续期,只能重新生成/申请,需保持「私钥不变、证书信息(域名、签发机构)与原证书一致」,避免修改Nginx、客户端配置,另注意私钥key文件不存在过期概念。
- 优先沿用原证书生成方案,例如原用方案3(CA+各应用证书),则仍用CA根证书重新签发,不切换方案;
- 操作顺序:先重新生成证书 → 替换Nginx证书 → 同步更新客户端(仅双向认证需更新客户端证书) → 验证有效性。
二、过期场景
针对方案3(CA根证书+各应用证书,推荐,过期),分两种情况:
-
仅各应用服务端证书过期(CA根证书未过期,最常见):
- 重新用CA根证书签发对应应用证书(沿用原应用私钥、路径、文件名),以订单中心为例:
cd /usr/local/ssl/ssl_order # 私钥(order.key)不变,重新生成证书请求文件(order.csr) openssl req -new -key order.key -out order.csr # 用CA根证书重新签发新证书(order.crt) openssl x509 -req -in order.csr -CA /usr/local/ssl/ssl_ca/ca.crt -CAkey /usr/local/ssl/ssl_ca/ca.key -CAcreateserial -out order.crt -days 3650 - 支付、商品中心同理,重新签发;
- 替换Nginx证书、平滑重启Nginx,客户端无需额外操作(因信任的是CA根证书,CA未过期,无需重新加载)。
- 重新用CA根证书签发对应应用证书(沿用原应用私钥、路径、文件名),以订单中心为例:
-
CA根证书过期(所有应用证书均失效):
- 先重新生成CA根证书(沿用原路径、原文件名,避免客户端改配置):
cd /usr/local/ssl/ssl_ca # 私钥(ca.key)不变,重新生成CA根证书(ca.crt) openssl req -new -x509 -key ca.key -out ca.crt -days 3650 - 再用新的CA根证书,重新签发所有应用的服务端证书(步骤同场景3第1点);
- 替换Nginx证书、重启Nginx;
- 客户端更新:所有信任CA根证书的客户端(微服务/浏览器/APP),需重新加载新的CA根证书(双向认证需同时更新客户端证书)。
- 先重新生成CA根证书(沿用原路径、原文件名,避免客户端改配置):