Spring实现HTTPS双向认证
目录
前言
一、单向认证和双向认证
二、创建keyStore和trustStore
三、服务端配置
四、客户端配置
总结
参考链接
前言
本篇博客讲的主要是双向认证,通过一些简单案例来展示双向认证的配置过程。有关单向认证和一些https配置,可以看看我的这篇博客,只有了解清楚单向认证之后,那么双向认证理解更加简单,因为双向认证基于单向认证配置,所以建议在做https双向认证之前,先把https单向认证搞清楚:
Spring实现HTTPS方式访问服务(单向认证)_明天再去学习的博客-CSDN博客
一、单向认证和双向认证
1、单向认证
单向认证十分简单,就是在服务端配置证书,客户端在向服务端发送请求时,服务端会发送一份自己的证书,由客户端进行验证,只要客户端通过验证,那么就能建立https链接。
2、双向认证
双向认证相比于单向认证多了一个步骤,那就是客户端发送请求时校验服务端的证书的同时,客户端也需要发送一份自己的证书给服务端进行校验,只有双方的证书在对方那里校验通过之后,才能建立起https链接。
二、创建keyStore和trustStore
1、keyStore与trustStore的作用
keyStore:
- keyStore是一个可以存储密钥、密钥对或证书的存储库。密钥:只有一个钥,一般是对称加密时使用;密钥对:包含公钥和私钥,一般是非对称加密时使用。
- keyStore文件的类型可以是JSK、PKCS12、JCEKS。JSK(Java Key Store)可以存储密钥对和证书;PKCS12、JCEKS都可以存储密钥、密钥对、证书。
- 在创建keyStore文件时,可以为keyStore设置密码。
- 密钥、密钥对、证书在keyStore统称为key,每一个key通过alias(别名)区分。key也可以设置密码(具体体现在keytool创建keyStore和trustStore时),keyStore可以存储多对key。
- 通过keytool成功往一个keyStore文件添加密钥对后,可以从该keyStore中获取到私钥、证书以及公钥(公钥主要以证书的形式存放)。
trustStore:
- trustStore中保存的是一些可信任的证书
- trustStore文件的类型可以是JSK、PKCS12、JCEKS。JSK(Java Key Store)可以存储密钥对和证书;PKCS12、JCEKS都可以存储密钥、密钥对、证书。
2、创建服务端keyStore和客户端trustStore(以下指令均在控制台执行)
注意:由于只是本地简单配置双向认证,涉及到的证书将由工具keytool生成,真正生产环境下的证书,将有认证过的CA机构去生成。
创建服务端keyStore
keytool -genkey -alias serverkey -keyalg RSA -keysize 2048 -sigalg SHA256withRSA -keystore serverkeystore.p12 -storepass 123456 -ext san=ip:127.0.0.1,dns:localhost
导出服务端证书
keytool -exportcert -keystore serverkeystore.p12 -alias serverkey -storepass 123456 -rfc -file server-certificate.pem
将服务端证书添加到客户端trustStore中
keytool -import -trustcacerts -file server-certificate.pem -keypass 123456 -storepass 123456 -keystore clienttruststore.jks
3、创建客户端keyStore和服务端trustStore
创建客户端keyStore
keytool -genkey -alias client -keyalg RSA -keysize 2048 -sigalg SHA256withRSA -keystore clientKeystore.p12 -storepass 123456 -ext san=ip:127.0.0.1
导出客户端证书
keytool -exportcert -keystore clientKeystore.p12 -alias client -storepass 123456 -rfc -file client-certificate.pem
将客户端证书添加到服务端trustStore中
keytool -import -trustcacerts -file client-certificate.pem -keypass 123456 -storepass 123456 -keystore serverTruststore.jks
4、生成结果
在后续实践中,我们需要用到的是 serverKeyStore、serverTrustStore、clientKeyStore、clientTrustStore
三、服务端配置
1、将serverKeyStore、serverTrustStore存放在resource目录下
2、application.yml配置如下
server:
port: 7050
ssl:
key-store: classpath:serverKeyStore.p12
key-store-password: 123456
key-store-type: PKCS12
key-alias: serverKey
client-auth: need
trust-store: classpath:serverTrustStore.jks
trust-store-password: 123456
trust-store-type: JKS
- key-store:用于指定你的keyStrore文件
- key-store-type:指定你的文件的类型,在上面说过,keyStore的类型可以是JKS、PKCS12、JCEKS
- key-store-password:就是你在通过keytool创建keyStore时指定的密码
- key-alias: 指定使用哪一个key
- client-auth:开启客户端验证,即需要验证客户端证书,服务端开启双向认证的开关
- trust-store:用于指定你的trustStrore(信任库)文件,客户端证书校验将在此处进行
- trust-store-type:指定你的文件的类型,在上面说过,trustStore的类型可以是JKS、PKCS12、JCEKS
- trust-store-password:就是你在通过keytool创建trustStore时指定的密码
至此,服务端https双向认证配置到此处结束,接下来是客户端的配置
四、客户端配置
1、将clientKeyStore、clientTrustStore存放在resource目录下:
2、导入以下依赖:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.6</version>
</dependency>
3、进行RestTemplate配置:
@Slf4j
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory httpComponentsClientHttpRequestFactory) {
RestTemplate restTemplate = new RestTemplate(httpComponentsClientHttpRequestFactory);
restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
return restTemplate;
}
@Bean("httpComponentsClientHttpRequestFactory")
public ClientHttpRequestFactory httpComponentsClientHttpRequestFactory() throws IOException, UnrecoverableKeyException, CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
final String allPassword = "123456";
TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
SSLContext sslContext = SSLContextBuilder
.create()
.loadKeyMaterial(new ClassPathResource("clientKeystore.p12").getURL(),
allPassword.toCharArray(), allPassword.toCharArray())
.loadTrustMaterial(new ClassPathResource("clientTruststore.jks").getURL(), allPassword.toCharArray())
.loadTrustMaterial(null, acceptingTrustStrategy)
.build();
HttpClient client = HttpClients.custom()
.setSSLContext(sslContext)
.build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(client);
// INSTANCE 忽略域名检查,证书中的域名与请求的域名不匹配时,验证通过, 不建议开启该功能,因为存在安全问题
/*SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
CloseableHttpClient httpclient = HttpClients
.custom()
.setSSLSocketFactory(sslConnectionSocketFactory)
.setSSLHostnameVerifier(new NoopHostnameVerifier())
.build();
requestFactory.setHttpClient(httpclient);*/
return requestFactory;
}
}
4、通过RestTempate进行接口调用,客户端能够与开启双向认证后的服务端进行连接访问。
至此,客户端的配置也完成了 。
总结
双向配置的精髓就是,客户端也需要配置自己的证书,在发送请求的同时,将自己的证书发送给服务端,让服务端去验证证书,所以,搞清楚双向认证配置之前,一定要先弄清楚单向认证配置,以达事半功倍。
参考链接
一文读懂Https的安全性原理、数字证书、单项认证、双项认证等 - 知乎
百度安全验证
还没有评论,来说两句吧...