使用Spring Boot SSL Bundle功能开发安全的REST API

本文详细介绍了如何在Spring Boot中使用自签名证书配置安全的REST API,包括服务器端HTTPS设置和客户端安全调用,涵盖密钥库生成、SSL配置和证书信任链的建立。

在Spring Boot中使用SSL保护REST API(服务器+客户端)

安全套接字层(SSL)是保护系统间通信的关键组件,特别是在分层或面向服务的架构中。在这样的环境中,典型的Spring Boot服务可能暴露一个REST端点,然后由另一个充当客户端的Spring Boot服务使用。当主机服务暴露安全端点时,必须确保只允许授权服务连接。

有几种方法可以保护REST端点,包括证书交换、JWT令牌和OAuth。本文将重点介绍使用自签名证书的基于证书的API保护。

在Spring Boot中托管安全API

要使用Spring Boot托管安全的REST API,服务需要经过几个关键步骤。首先,必须生成证书签名请求(CSR)并由受信任的证书颁发机构(CA)签名。

作为此过程的一部分,通常会收到三个证书:

  • 主机证书
  • 中间证书
  • 根证书

这三个证书然后组合形成证书链,确保客户端可以验证整个信任路径——从您的服务一直到根机构。

对于本文,我们不会使用受信任机构签名的证书。相反,我们将创建一个自签名证书。自签名证书通常用于在非生产环境中托管和测试HTTPS API。然而,对于生产环境,最佳实践是使用由受信任证书颁发机构(CA)签名的证书。

创建自签名证书的步骤

1. 生成密钥库文件

密钥库文件就像一个安全数据库,用于存储加密密钥和证书。它可以是.JKS(Java密钥库)格式或.P12/.PFX(PKCS12)格式。

要生成密钥库,我们将使用keytool命令,该命令随JDK安装一起提供。

1
keytool -genkeypair -alias mylocalsslapp -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore mysslapp.p12 -validity 365
  • Keytool指的是keytool.exe,它位于%JAVA_HOME%\bin文件夹中
  • 命令用于生成加密密钥
  • 要处理的条目的别名
  • 用于加密和解密的算法
  • 密钥位大小
  • 密钥库类型,可以是PKCS12或JKS
  • 密钥库文件名
  • 有效天数

创建证书时,需要提供以下详细信息,证书颁发机构将验证这些详细信息以签署您的证书请求。

此命令成功运行后,您将在当前工作目录中看到创建的mysslapp.p12文件。

您可以使用以下命令查看生成的证书内容:

现在您的证书已准备好在Spring Boot服务器应用程序中使用。

服务器上的SSL配置

Spring Boot使得配置和暴露HTTPS API变得容易。随着最近SSL Bundle的引入,使用和管理自定义SSL信任材料(如密钥库、证书和私钥)现在更加简单。SSL Bundle允许您使用标准Spring Boot API跨一个或多个连接应用SSL配置。

创建REST服务

让我们首先创建一个简单的userService,它将返回一些静态用户数据。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
@RestController
@RequestMapping("/UserService")
public class UserController {

    @GetMapping("/userDetails")
    public Map<String,String> getUserData(){
        Map<String,String> userMap = new HashMap<>();
        userMap.put("firstName","Bob");
        userMap.put("lastName","Wilson");
        userMap.put("department","security");
        userMap.put("phoneNumber","123-456-7890");

        return userMap;
    }
}

使用密钥库配置SSL属性

将以下条目添加到Spring Boot服务器应用程序的application.properties文件中,以使用密钥库启用HTTPS:

1
2
3
4
5
6
server.port=8443
server.ssl.bundle=sslbundle
spring.ssl.bundle.jks.sslbundle.key.alias=mylocalsslapp
spring.ssl.bundle.jks.sslbundle.keystore.location=classpath:mysslapp.p12
spring.ssl.bundle.jks.sslbundle.keystore.password=myappsecret
spring.ssl.bundle.jks.sslbundle.keystore.type=PKCS12

提供与之前创建密钥库时使用的相同密钥库密码。然后,将mysslapp.p12证书复制到Spring Boot项目的resources文件夹中。

完成这些步骤后,您就可以启动微服务并从浏览器测试/UserService端点了。

当您使用以下URL导航到安全端点时,您的浏览器可能会显示警告。只需单击"接受风险"(或类似选项)继续。然后您应该看到服务返回的响应,确认您的API现在可以通过HTTPS访问。

此时,您已成功使用自签名证书设置了安全的REST服务。

您可以在GitHub上的以下位置找到此示例的相应代码:

从Spring Boot客户端服务调用安全API

现在您的安全端点已启动并运行,下一步是配置一个可以调用此HTTPS端点的Spring Boot客户端服务。为此,客户端必须信任服务器使用的证书。

从服务器导出证书

服务器应用程序需要向客户端提供其证书。此证书将由客户端在发出安全API调用时用于验证服务器。

在服务器上使用以下命令从密钥库导出证书:

1
keytool -exportcert -alias mylocalsslapp -keystore mysslapp.p12 -storetype PKCS12 -storepass ****** -file client.crt -rfc

此步骤将在执行命令的位置创建一个client.crt文件。此证书文件应与客户端应用程序共享。

在客户端服务中配置证书

客户端收到证书后,应将.crt文件复制到客户端应用程序的resources文件夹中。

接下来,将以下条目添加到客户端服务的application.properties文件中:

1
spring.ssl.bundle.pem.clientbundle.truststore.certificate=classpath:client.crt

如果您使用RestTemplate调用安全的REST端点,可以使用SSL bundle创建RestTemplate实例,如下所示:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@Service
public class MyService {
    private final RestTemplate restTemplate;

    public MyService(RestTemplateBuilder restTemplateBuilder, SslBundles sslBundles) {
        this.restTemplate = restTemplateBuilder.sslBundle(sslBundles.getBundle("clientbundle")).build();
    }

    public RestTemplate getRestTemplate() {
        return restTemplate;
    }
}

现在,让我们在客户端服务中暴露另一个端点,该端点将在内部调用服务器应用程序托管的的安全端点。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@RestController
@RequestMapping("/UserService")
public class UserController {

    @Autowired
    private MyService myService;

    @GetMapping("/userDetails")
    public String getUserData(){
        return myService.getRestTemplate().getForObject("https://localhost:8443/UserService/userDetails", String.class);
    }
}

让我们调用客户端端点,该端点充当安全服务器端点的消费者。

通过此示例,我们成功设置了一个托管安全HTTPS端点的服务器应用程序,以及一个安全使用该端点的客户端应用程序。

您可以在以下GitHub存储库中找到服务器和客户端应用程序的完整代码。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计