Spring实现HTTPS方式访问服务(单向认证)

目录

前言

一、基本概念

二、创建keyStore、trustStore

三、服务端配置

四、客户端配置

总结

参考链接


前言

本文通过Spring来配置https服务,后续会将相关的知识内容简单讲解一下,该文章主要是https单向认证,双向认证实现过程将在后续不久的另外一边文章涉及,感兴趣的小伙伴可以提前提供关注一下。

在我们搭建的web服务中,如果没有去配置过https相关的配置,那么该服务只是一个普通的http服务,如果想要该服务成为一个https服务,通过https的方式访问接口的话,那么首先需要的是生成证书,公钥,私钥等相关内容,再进行https配置了,在开始实现之前,我们需要简单了解一下什么是HTTP,HTTPS,SSL/TLS,数字证书,公钥/私钥,keyStore, trustStore等简单的概念。


一、基本概念

友情提示:以下概述均摘自百度百科加其他文章参考,参考链接将放到最下面。

1、HTTP:

超文本传输协议(Hyper Text Transfer Protocol,HTTP)是一个简单的请求-响应协议,它通常运行在TCP之上。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。

2、HTTPS:

HTTPS (全称:Hypertext Transfer Protocol Secure ),是以安全为目标的 HTTP 通道,在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性 。HTTPS 在HTTP 的基础下加入SSL,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL。 HTTPS 存在不同于 HTTP 的默认端口及一个加密/身份验证层(在 HTTP与 TCP 之间),HTTP默认端口是80,HTTPS默认端口是443。

HTTPS相对HTTP提供了更安全的数据传输保障,主要体现在三个方面:

1)内容加密:客户端到服务器的内容都是以加密形式传输,中间者无法直接查看明文内容;

2)身份认证:通过校验保证客户端访问的是自己的服务器;

3)数据完整性:防止内容被第三方冒充或者篡改。

3、SSL/TLS:

TLS是传输层加密协议,前身是SSL协议。由网景公司于1995年发布。后改名为TLS。常用的 TLS 协议版本有:TLS1.2, TLS1.1, TLS1.0 和 SSL3.0。其中 SSL3.0 由于 POODLE 攻击已经被证明不安全。TLS1.0 也存在部分安全漏洞,比如 RC4 和 BEAST 攻击。

4、数字证书:

数字证书是指在互联网通讯中标志通讯各方身份信息的一个数字认证,在网上用它来识别对方的身份。因此数字证书又称为数字标识。数字证书对网络用户在计算机网络交流中的信息和数据等以加密或解密的形式保证了信息和数据的完整性和安全性。在建立HTTPS链接过程中,需要传递数字证书对服务进行认证。

5、公钥/私钥:

公钥是与私钥算法一起使用的密钥对的非秘密一半。公钥通常用于加密会话密钥、验证数字签名,或加密可以用相应的私钥解密的数据。公钥和私钥是通过一种算法得到的一个密钥对(即一个公钥和一个私钥),其中的一个向外界公开,称为公钥;另个自己保留,称为私钥。通过这种算法得到的密钥对能保证在世界范围内是唯一的。使用这个密钥对的时候,如果用其中一个密钥加密一段数据,必须用另一个密钥解密。如用公钥加密数据就必须用私钥解密,如果用私钥加密也必须用公钥解密,否则解密将不会成功 。

6、keyStore:

keyStore是一个可以存储密钥、密钥对或证书的存储库。

  • 密钥:只有一个钥,一般是对称加密时使用
  • 密钥对:包含公钥和私钥,一般是非对称加密时使用
  • 证书,即数字证书,用于网络上进行身份验证

keyStore文件的类型可以是JSK、PKCS12、JCEKS

  • JKS(Java Key Store)可以存储密钥对和证书
  • PKCS12、JCEKS都可以存储密钥、密钥对、证书

在创建keyStore文件时,可以为keyStore设置密码

密钥、密钥对、证书在keyStore统称为key,每一个key通过alias(别名)区分。key也可以设置密码(具体体现在keytool创建keyStore和trustStore时),keyStore可以存储多对key

通过keytool成功往一个keyStore文件添加密钥对后,可以从该keyStore中获取到私钥、证书以及公钥(公钥主要以证书的形式存放)。

7、trustStore:

trustStore中保存的是一些可信任的证书

trustStore文件的类型可以是JSK、PKCS12、JCEKS

二、创建keyStore、trustStore

1、创建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

在控制台执行该命令,用需要输入一些基本信息,按要求输入即可,从keyStore中可以获取到证书、公钥、私钥

2、创建trustStore

 1)从keyStore中导出证书

keytool -exportcert -keystore serverKeystore.p12 -alias serverKey -storepass 123456 -rfc -file server-certificate.pem

2)将证书添加到trustStore中

keytool -import -trustcacerts -file server-certificate.pem -keypass 123456 -storepass 123456 -keystore clientTruststore.jks

3、生成结果

执行完上述指令后,在目录下生成的文件如下:

上图中我们只需要关注serverKeystore(keyStore)和clientTruststore(trustStore)

  • serverKeystore用于在服务端进行配置,serverKeystore提供证书、私钥、公钥
  • clientTruststore用于在客户端进行配置,当该客户端收到服务端的证书时,将会从clientTruststore中与服务端的证书进行比对

三、服务端配置

首先是将服务端搭建成以https方式访问的web服务,这里我们默认服务就是一个spring boot服务了,有关spring boot服务怎么搭建,不是本文重点,本文着重于https相关配置

1、将证书serverKeystore.p12存放到resource目录下

2、application.yml配置如下

server:
  port: 8000
  ssl:
    key-store: classpath:serverkeystore.p12
    key-store-type: PKCS12
    key-store-password: 123456
    key-alias: serverKey

key-store:用于指定你的keyStrore文件

key-store-type:指定你的文件的类型,在上面说过,keyStore的类型可以是JKS、PKCS12、JCEKS

key-store-password:就是你在通过keytool创建keyStore时指定的密码

key-alias: 指定使用哪一个key

3、启动服务进行验证

随便写个接口进行调用,这里就不展示代码出来了

以http方式访问结果如下:

如图,提示我们需要通过https的方式去访问该接口

以https方式访问结果如下:

 可以看到,浏览器提示不安全,那是因为颁发证书的机构是我们自己,是浏览器不认可的,正常情况下证书的颁发是由合法的CA机构来做的

至此,服务端https搭建完成,接来下就是展示客户端调用https接口的解决方案了,感兴趣的小伙伴可以接着往下看

四、客户端配置

对于客户端来说,调用https接口时,会接收到服务端传送过来的证书,我们有两种解决方案一是校验证书的合法性,二是忽略对证书的校验,以下将通过案例进行展示

在没有进行有关https的配置时,直接调用服务端接口,你会看到控制台报一下错误:

sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

这是因为我们在接收到服务端的证书之后,却没有进行任何处理,导致报错,以下将提供两种解决方案步骤

1、方案一:校验证书合法性

1)将clientTruststore存放到客户端服务的resource目录下

2)引入以下依赖

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.6</version>
</dependency>

3) application.yml的配置如下

server:
  port: 9000

这里有一点需要提示,在配置文件中,server.ssl.trust-store可以对trustStore进行配置,但客户端在这里配置是没有用的,因为该配置是用于双向认证中服务端进行配置的,服务端在此处配置trustStore,可以用于校验客户端的证书。如果你的客户端同时也作为服务端向外提供服务,也需要校验其他服务的证书的话,那么,此时你就需要配置server.ssl.trust-store了

而客户端作为发起请求方,对于证书的校验,应该在发起请求的工具上进行完成,在本文中使用的是RestTemplate,接下来将对RestTemplate进行配置

4)RestTemplate配置

@Configuration
@Slf4j
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()
                .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;
    }
}

5)通过该RestTemplate实例去调用服务端接口,就可以发现能够正常调用

2、方案二:直接忽略证书校验

忽略对证书的校验,可以看我这一篇博客,通过文章中的配置,就可以忽略对服务端证书的校验,直接相信它就是服务端

RestTemplate发送请求,配置HTTPS请求忽略SSL证书_明天再去学习的博客-CSDN博客_resttemplate 忽略ssl


总结

通过本文章简单描述了https服务搭建以及单向认证的实现的过程,接下来将会出一篇博客,实现https双向认证,双向认证与单向认证之间存在着紧密联系,清楚了单向认证实现流程,那么,双向认证也不在话下了。

参考链接

https://zhuanlan.zhihu.com/p/36527074

KeyStore是什么_markix的博客-CSDN博客_keystore

[SpringBoot]实战配置Https证书和RestTemplate配置Https双向认证 - 简书

  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值