【问题标题】:Enable HTTPS with self-signed certificate in Spring Boot 2.0在 Spring Boot 2.0 中使用自签名证书启用 HTTPS
【发布时间】:2018-08-25 18:06:18
【问题描述】:

我正在关注this tutorial,以使用自签名证书在 Spring Boot 2.0 中启用 HTTPS,仅用于测试目的。总之,该教程包括以下步骤:

1.使用keytool生成密钥库。

keytool -genkey -alias tomcat
 -storetype PKCS12 -keyalg RSA -keysize 2048
 -keystore keystore.p12 -validity 3650

2.通过在application.properties文件中添加一些属性在Spring Boot中启用HTTPS。

server.port: 8443
server.ssl.key-store: keystore.p12
server.ssl.key-store-password: mypassword
server.ssl.keyStoreType: PKCS12
server.ssl.keyAlias: tomcat

3. 将 HTTP 重定向到 HTTPS(可选)。我忽略了这部分。

但是当我启动我的应用程序时,我得到了这些错误:

org.apache.catalina.LifecycleException: Failed to start component [Connector[HTTP/1.1-8443]]
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:167) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
    at org.apache.catalina.core.StandardService.addConnector(StandardService.java:225) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
    at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.addPreviouslyRemovedConnectors(TomcatWebServer.java:255) [spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]
    at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.start(TomcatWebServer.java:197) [spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.startWebServer(ServletWebServerApplicationContext.java:300) [spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.finishRefresh(ServletWebServerApplicationContext.java:162) [spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:552) [spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140) [spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752) [spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:388) [spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:327) [spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1246) [spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1234) [spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]
    at epic.gwdg.restgraph.RestgraphApplication.main(RestgraphApplication.java:10) [classes/:na]
Caused by: org.apache.catalina.LifecycleException: Protocol handler start failed
    at org.apache.catalina.connector.Connector.startInternal(Connector.java:1021) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
    ... 13 common frames omitted
Caused by: java.lang.IllegalArgumentException: Private key must be accompanied by certificate chain
    at org.apache.tomcat.util.net.AbstractJsseEndpoint.createSSLContext(AbstractJsseEndpoint.java:116) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
    at org.apache.tomcat.util.net.AbstractJsseEndpoint.initialiseSsl(AbstractJsseEndpoint.java:87) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
    at org.apache.tomcat.util.net.NioEndpoint.bind(NioEndpoint.java:225) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
    at org.apache.tomcat.util.net.AbstractEndpoint.start(AbstractEndpoint.java:1150) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
    at org.apache.coyote.AbstractProtocol.start(AbstractProtocol.java:591) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
    at org.apache.catalina.connector.Connector.startInternal(Connector.java:1018) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
    ... 14 common frames omitted
Caused by: java.lang.IllegalArgumentException: Private key must be accompanied by certificate chain
    at java.base/java.security.KeyStore.setKeyEntry(KeyStore.java:1170) ~[na:na]
    at org.apache.tomcat.util.net.jsse.JSSEUtil.getKeyManagers(JSSEUtil.java:257) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
    at org.apache.tomcat.util.net.AbstractJsseEndpoint.createSSLContext(AbstractJsseEndpoint.java:114) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
    ... 19 common frames omitted

2018-03-16 16:42:30.917  INFO 970 --- [           main] o.apache.catalina.core.StandardService   : Stopping service [Tomcat]
2018-03-16 16:42:30.931  INFO 970 --- [           main] ConditionEvaluationReportLoggingListener : 

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2018-03-16 16:42:30.933 ERROR 970 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

The Tomcat connector configured to listen on port 8443 failed to start. The port may already be in use or the connector may be misconfigured.

Action:

Verify the connector's configuration, identify and stop any process that's listening on port 8443, or configure this application to listen on another port.

2018-03-16 16:42:30.934  INFO 970 --- [           main] ConfigServletWebServerApplicationContext : Closing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@58ce9668: startup date [Fri Mar 16 16:42:26 CET 2018]; root of context hierarchy
2018-03-16 16:42:30.936  INFO 970 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Unregistering JMX-exposed beans on shutdown

Process finished with exit code 1

基本上,消息是:

私钥必须伴随证书链。

这是一个自签名证书,所以它当然没有可信链。我该如何解决?

这是我当前的application.properties 文件:

server.port=8443
server.ssl.enabled=true
server.ssl.key-store=classpath:keystore.p12
server.ssl.key-password=123456
server.ssl.key-store-type=PKCS12
server.ssl.key-alias=tomcat

非常感谢您的帮助。

【问题讨论】:

    标签: java spring-boot https keystore keytool


    【解决方案1】:

    问题在于,在您生成的密钥库中,您没有密钥对,因此没有私钥,这是因为您使用选项 -genkey 您需要通过选项 -genkeypair 更改它:

    -genkey 生成一个密钥,而 -genkeypair 生成一个 密钥对(公钥和私钥)。

    所以我认为这应该可行:

    keytool -genkeypair -alias tomcat -storetype PKCS12 -keyalg RSA -keysize 2048  -keystore keystore.p12 -validity 3650
    

    在您的 spring boot 配置中,将“:”更改为“=”并添加到您的密钥库的路径我想您的 keystore.p12 在您的资源文件夹中:

    server.ssl.key-store = classpath:keystore.p12
    server.ssl.key-store-password = mypassword
    server.ssl.key-store-type = PKCS12
    server.ssl.key-alias = tomcat
    

    【讨论】:

    • 谢谢,但我还是有同样的问题:(
    • 我更新了我的响应,在你的 spring 属性 conf 中通过 "=" 更改 ":" 并为参数 "server.ssl.key-store" 添加密钥库的路径
    • 其实我在我的配置中使用了“=”和“classpath”。两种方法我都试过了,错误仍然存​​在...
    • 我再次更新我的回复有另一个问题再次将“server.ssl.keyStoreType”= PKCS12 更改为“server.ssl.key-store-type=PKCS12”
    • 我刚刚更新了我的问题以添加我的配置。我注意到密码字段应该是key-store-password,就像你的一样。我改了,好用!!!您可以更新您的答案 (key-alias)。我会将您的答案标记为正确。谢谢你:)
    【解决方案2】:

    我在带有嵌入式 Tomcat 服务器的 Spring Boot 应用程序上也遇到了这个可怕的 Private key must be accompanied by certificate chain 错误。这让我疯了

    原来一个简单的错字是我的问题:

    @Override
    public void customize(ConfigurableServletWebServerFactory server) {
        Ssl ssl = new Ssl();
        ssl.setEnabled(true);
        ssl.setKeyStore(keystoreFile);
        ssl.setKeyPassword(keystorePass); // << Should be `setKeyStorePassword` !!!!
        ssl.setKeyStoreType(keystoreType);
        ssl.setKeyAlias(keystoreAlias);
    
        server.setSsl(ssl);
        server.setPort(sslPort);
    }
    

    因此,对于这种情况,错误消息根本没有帮助。我希望这对其他人有帮助。请务必确认您将正确的密码(密钥与密钥库)放在正确的位置。同样的问题也可能发生在基于属性的设置中 - 这取决于您使用的内容。

    【讨论】:

      【解决方案3】:

      您在 application.properties 文件中犯了一个小错误。请更改

      server.ssl.key-password=your_password
      

      server.ssl.key-store-password=your_password
      

      然后它会正常工作。希望能帮助到你!谢谢!

      【讨论】:

      • 谢谢,只有这个改变解决了我的问题。仍然不知道为什么,因为我有另一个自签名证书并且使用server.ssl.key-password=your_password 工作...
      【解决方案4】:

      1.使用“-genkeypair”

      keytool -genkeypair -alias tomcat -storetype PKCS12 -keyalg RSA -keysize 2048  -keystore keystore.p12 -validity 3650
      
      1. 将“server.ssl.key-password”更改为“server.ssl.key-store-password

      【讨论】:

      • 第二部分 +1。我认为在更高版本的 Springboot 中进行了一些重命名,但遗憾的是错误消息并没有说明无法正确读取密码。
      【解决方案5】:

      Spring Boot 2.2.1.RELEASE

      keytool -genkeypair -keystore myKeystore2.p12 -storetype PKCS12 -storepass 123456 -alias ks-localhost -keyalg RSA -keysize 2048 -validity 99999 -dname "CN=My SSL Certificate, OU=My Team, O=My Company, L=My City, ST=My State, C=SA" -ext san=dns:localhost,ip:127.0.0.1
      

      application.yml

      server:
        tomcat:
          accesslog:
            enabled: true
        ssl:
          key-store-type: PKCS12
          key-store: classpath:myKeystore.p12
          key-alias: ks-localhost
          enabled: true
          protocol: TLS
          key-store-password: 123456
      

      【讨论】:

        【解决方案6】:

        我遇到了类似的问题,在我的情况下,我缺少信任存储中的 trustAnchors。

        一种解决方案是使用 java 内置 keytool,如其他答案中所述。但是还有一个使用KeyStore Explorer GUI 的更简单的方法,所以我将解释使用这两个工具的完整步骤。

        1.首先,如答案所述,我们需要在application.properties文件中启用SSL:

        # <======= SSL Security ===========>
        # Keystore config
        server.ssl.key-store-type=PKCS12
        server.ssl.key-store-password=change_it!
        server.ssl.key-store=classpath:keystore.p12
        server.ssl.key-alias=alias
        server.ssl.enabled=true
        
        # Trust Store Certificates
        server.ssl.trust-store=classpath:trust_store.p12
        server.ssl.trust-store-type=PKCS12
        server.ssl.trust-store-password=07123e1f482356c415f684407
        # <=====================>
        

        密钥库是服务器用来与客户端进行安全通信的公钥 - 私钥对的容器。客户端当然必须有公钥才能与服务器通信。

        信任库只是证书的容器。 (公钥)。 在我们的例子中,它将只包含一个证书,即服务器使用的那个。

        2.1 使用 java keytool 创建密钥库:

        keytool -genkeypair -alias alias -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore keystore.p12 -validity 3650
        

        2.2 导出证书,以便我们可以使用它来创建信任库密钥库

        keytool -export -keystore keystore.p12 -alias alias -file certificate.cer
        

        2.3 此步骤将使用导入的可信证书自动创建一个新的密钥库。 (该工具会询问您新密钥库的密码,当它询问“信任此证书?”时,您当然应该输入“是”)

        keytool -importcert -file certificate.cer -keystore trust_store.p12 -alias alias
        

        最后将两个密钥库保存在 Spring Boot 应用程序的资源文件夹中(如替代方法所示)。

        KeyStore Explorer 的替代方法

        2.1 使用 KeyStore Explorer 创建密钥库,如屏幕截图所示:

        然后将密钥库保存在 Spring Boot 应用程序的资源文件夹中:

        2.2 现在我们需要创建信任存储,它可以提供给需要与我们的服务器通信的客户端。首先提取由 KeyStore Explorer 创建的证书链,然后创建一个新的 KeyStore,将证书导入其中,如屏幕截图所示:

        然后创建我们的信任库,点击“创建一个新的KeyStore”,PKCS12格式如上一步,点击红色图标“导入信任证书”,选择上一步保存的证书,最后就像我们在第一次创建密钥库时所做的那样,将密钥库保存在资源文件夹中。

        现在您的服务器将启用与 SSL 安全通信。请记住,您的客户端必须配置为加载您创建的信任库。

        【讨论】:

          【解决方案7】:

          我遇到了同样的问题。我从第二个答案进行了更改。但问题并没有消失。 毕竟我做了,我只是将我的 keystore.p12 证书包含到 pom.xml 的 profiles 部分

              <profiles>
              <!-- DEVELOPMENT PROFILE -->
              <profile>
                  <id>dev</id>
                  <activation>
                      <activeByDefault>true</activeByDefault>
                  </activation>
                  <build>
                      <resources>
                          <resource>
                              <directory>src/main/resources</directory>
                              <includes>
                                  <include>application.properties</include>
                                  <include>keystore.p12</include>
                                  <include>data/**</include>
                              </includes>
                          </resource>
                      </resources>
                  </build>
              </profile>
          </profiles>
          

          【讨论】: