如何在 spring 启动时配置 ssl?
How to configure ssl in spring boot?
我需要 restful 服务在 spring 启动时支持 ssl。虽然服务应用程序启动成功,但我无法访问Chrome(版本:68.0.3440.106)中的页面。错误信息:ERR_SSL_VERSION_OR_CIPHER_MISMATCH
错误信息截图:
项目pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>test</groupId>
<artifactId>spring-restful-server-https</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<properties>
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
配置文件(密码被故意屏蔽):
server.port=8443
server.ssl.key-store=classpath:shq.jks
server.ssl.key-store-password=******
server.ssl.key-password=******
控制器class:
package test.spring_restful_server_https;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class GreetingController {
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();
@RequestMapping("/greeting")
public Greeting greeting(@RequestParam(value="name", defaultValue="World") String name) {
return new Greeting(counter.incrementAndGet(),
String.format(template, name));
}
}
我使用 java keytool 生成 shq.jks 文件。
密钥工具命令:
keytool -genkeypair -alias shq -keystore shq.jks
执行后:
keytool -list -keystore shq.jks -v
jks文件信息(我的环境是中文的,所以我翻译了信息并在括号中):
密钥库类型(keystore type): JKS
密钥库提供方(keystore provider): SUN
您的密钥库包含 1 个条目(your keystore contains 1 entry)
别名(alias name): shq
创建日期(creation date): 2018-8-16
条目类型(entry type): PrivateKeyEntry
证书链长度(certificate chain length): 1
证书(certificate)[1]:
所有者(owner): CN=shq, OU=home, O=home, L=shanghai, ST=shanghai, C=cn
发布者(issuer): CN=shq, OU=home, O=home, L=shanghai, ST=shanghai, C=cn
序列号(serial number): 279abe96
有效期开始日期(valid from): Thu Aug 16 21:02:31 CST 2018, 截止日期(until): Wed Nov 14 21:02:31 CST 2018
证书指纹(certificate fingerprints):
MD5: 78:E1:91:21:04:AC:38:F1:0B:30:D8:51:69:FD:BE:28
SHA1: 8A:D5:1C:26:69:6B:5C:50:75:A6:E8:BE:66:2F:58:01:68:8F:78:1A
SHA256: 74:0F:F1:0D:59:75:93:3B:BD:55:75:3D:F1:E8:23:17:CE:5D:C0:14:63:0D:D9:53:54:29:C2:C4:70:5A:82:C0
签名算法名称(signature algorithm name): SHA1withDSA
版本(version): 3
扩展(extensions):
#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: AF 9F 16 35 95 36 FD 13 0C EA 19 F8 A0 D0 E3 6F ...5.6.........o
0010: A6 CB BB EE ....
]
]
keytool -genkeypair
默认创建一个 DSA 密钥和(自签名)证书,并且 Chrome 显然不再支持任何使用 DSA 的密码套件(SSL/TLS 为歇斯底里的葡萄干调用 DSS)。我知道它过去确实如此,因为我曾经那样使用过它,但我确定最后一次是很久以前的事了。要修复 that 添加 -keyalg rsa
。此外,如果您使用的不是 Java 的当前或最新版本,keytool
可能默认为 1024 位,这已被官方禁止(不安全)好几年了(尽管我 漂亮 确定 Chrome 尚未对手动输入的证书强制执行);为了安全起见还加上-keysize 2048
。
但这还不够。 keytool -genkeypair
默认情况下创建一个没有扩展名的证书,特别是 没有 'SAN' 扩展名 (主题备用名称)。自本世纪初以来,SAN 一直被推荐用于 HTTPS 证书,并且截至去年 Chrome 要求 它。幸运的是,如果 add -ext SAN=type:value[,...]
,最新版本的 keytool
可以生成 SAN。但请注意 SAN 中的值必须匹配 用于连接 的名称 :如果您告诉浏览器 https://127.0.0.1:port/
,如中所示您的 post,证书的 SAN 必须包含 IP:127.0.0.1
的条目;像 DNS:myhost.foo
这样的域名条目是一个不同的名称并且不匹配并且不会被接受,即使 myhost.foo
解析为地址 127.0.0.1。 SAN 支持多个条目,因此如果您愿意,您可以拥有一个或多个 IPand/or 一个或多个 DNS。 (如果您使用其他浏览器,您现在可以省略 SAN,if 您确实使主题字段 'CN'(通用名称)匹配(并且它只能包含一个值),但我不会打赌还能持续多久。)
如果你不知道,因为你没有提到它,一个像 keytool
生成的自签名证书(或者像 openssl req -new -x509
这样的许多其他东西,你'我会在整个网络上找到,包括 Stack 上的此处)默认情况下将被视为不受信任和无效。在它被信任之前,您必须将它添加到浏览器的信任库中。由于 Chrome 使用底层系统的信任库,您可以通过 Chrome 或其他方式执行此操作,具体取决于您未识别的系统。
如果您要从其他客户端访问它,正如我假设的那样,不同客户端使用的信任库通常取决于客户端,对此您什么也没说。
已添加:看起来这发生在 2016 年;他们删除了所有 DHE 密钥交换作为防止太小的 DHE aka Logjam 的粗略方法,并且唯一的 DSA (DSS) 密钥交换需要 DHE。 https://bugs.chromium.org/p/chromium/issues/detail?id=619194
我需要 restful 服务在 spring 启动时支持 ssl。虽然服务应用程序启动成功,但我无法访问Chrome(版本:68.0.3440.106)中的页面。错误信息:ERR_SSL_VERSION_OR_CIPHER_MISMATCH
错误信息截图:
pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>test</groupId>
<artifactId>spring-restful-server-https</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<properties>
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
配置文件(密码被故意屏蔽):
server.port=8443
server.ssl.key-store=classpath:shq.jks
server.ssl.key-store-password=******
server.ssl.key-password=******
控制器class:
package test.spring_restful_server_https;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class GreetingController {
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();
@RequestMapping("/greeting")
public Greeting greeting(@RequestParam(value="name", defaultValue="World") String name) {
return new Greeting(counter.incrementAndGet(),
String.format(template, name));
}
}
我使用 java keytool 生成 shq.jks 文件。
密钥工具命令:
keytool -genkeypair -alias shq -keystore shq.jks
执行后:
keytool -list -keystore shq.jks -v
jks文件信息(我的环境是中文的,所以我翻译了信息并在括号中):
密钥库类型(keystore type): JKS
密钥库提供方(keystore provider): SUN
您的密钥库包含 1 个条目(your keystore contains 1 entry)
别名(alias name): shq
创建日期(creation date): 2018-8-16
条目类型(entry type): PrivateKeyEntry
证书链长度(certificate chain length): 1
证书(certificate)[1]:
所有者(owner): CN=shq, OU=home, O=home, L=shanghai, ST=shanghai, C=cn
发布者(issuer): CN=shq, OU=home, O=home, L=shanghai, ST=shanghai, C=cn
序列号(serial number): 279abe96
有效期开始日期(valid from): Thu Aug 16 21:02:31 CST 2018, 截止日期(until): Wed Nov 14 21:02:31 CST 2018
证书指纹(certificate fingerprints):
MD5: 78:E1:91:21:04:AC:38:F1:0B:30:D8:51:69:FD:BE:28
SHA1: 8A:D5:1C:26:69:6B:5C:50:75:A6:E8:BE:66:2F:58:01:68:8F:78:1A
SHA256: 74:0F:F1:0D:59:75:93:3B:BD:55:75:3D:F1:E8:23:17:CE:5D:C0:14:63:0D:D9:53:54:29:C2:C4:70:5A:82:C0
签名算法名称(signature algorithm name): SHA1withDSA
版本(version): 3
扩展(extensions):
#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: AF 9F 16 35 95 36 FD 13 0C EA 19 F8 A0 D0 E3 6F ...5.6.........o
0010: A6 CB BB EE ....
]
]
keytool -genkeypair
默认创建一个 DSA 密钥和(自签名)证书,并且 Chrome 显然不再支持任何使用 DSA 的密码套件(SSL/TLS 为歇斯底里的葡萄干调用 DSS)。我知道它过去确实如此,因为我曾经那样使用过它,但我确定最后一次是很久以前的事了。要修复 that 添加 -keyalg rsa
。此外,如果您使用的不是 Java 的当前或最新版本,keytool
可能默认为 1024 位,这已被官方禁止(不安全)好几年了(尽管我 漂亮 确定 Chrome 尚未对手动输入的证书强制执行);为了安全起见还加上-keysize 2048
。
但这还不够。 keytool -genkeypair
默认情况下创建一个没有扩展名的证书,特别是 没有 'SAN' 扩展名 (主题备用名称)。自本世纪初以来,SAN 一直被推荐用于 HTTPS 证书,并且截至去年 Chrome 要求 它。幸运的是,如果 add -ext SAN=type:value[,...]
,最新版本的 keytool
可以生成 SAN。但请注意 SAN 中的值必须匹配 用于连接 的名称 :如果您告诉浏览器 https://127.0.0.1:port/
,如中所示您的 post,证书的 SAN 必须包含 IP:127.0.0.1
的条目;像 DNS:myhost.foo
这样的域名条目是一个不同的名称并且不匹配并且不会被接受,即使 myhost.foo
解析为地址 127.0.0.1。 SAN 支持多个条目,因此如果您愿意,您可以拥有一个或多个 IPand/or 一个或多个 DNS。 (如果您使用其他浏览器,您现在可以省略 SAN,if 您确实使主题字段 'CN'(通用名称)匹配(并且它只能包含一个值),但我不会打赌还能持续多久。)
如果你不知道,因为你没有提到它,一个像 keytool
生成的自签名证书(或者像 openssl req -new -x509
这样的许多其他东西,你'我会在整个网络上找到,包括 Stack 上的此处)默认情况下将被视为不受信任和无效。在它被信任之前,您必须将它添加到浏览器的信任库中。由于 Chrome 使用底层系统的信任库,您可以通过 Chrome 或其他方式执行此操作,具体取决于您未识别的系统。
如果您要从其他客户端访问它,正如我假设的那样,不同客户端使用的信任库通常取决于客户端,对此您什么也没说。
已添加:看起来这发生在 2016 年;他们删除了所有 DHE 密钥交换作为防止太小的 DHE aka Logjam 的粗略方法,并且唯一的 DSA (DSS) 密钥交换需要 DHE。 https://bugs.chromium.org/p/chromium/issues/detail?id=619194