在 Spring Boot 3 中验证客户端证书

Validate client certificate in Spring boot 3

提问人:Anthony Vinay 提问时间:11/10/2023 最后编辑:Anthony Vinay 更新时间:11/13/2023 访问量:56

问:

Java 应用程序正在使用 Spring Boot 3 和 Java 17,其中公开了一些 REST API。进行 API 调用时,仅针对特定端点,我想提取客户端证书并对其进行验证。

curl 命令调用 API :

curl -X POST "https://localhost:8443/api/auth" \
    -H "accept: */*" \
    -H "Content-Type: application/json" \
    -H "skv_client_correlation_id: xyz" \
    -d '{"xyz": "xyz"}' \
    --cert client_public_certificate.crt \
    --key client_private_key.key \
    --cacert server_public_certificate.crt

在升级到 Spring Boot 3 之前,在 Spring Boot 2 中,客户端证书已通过以下方式进行验证:

public class CertificateFilter extends OncePerRequestFilter {

    private final KeyStore keyStore;

    @Override
    protected void doFilterInternal(
        @NonNull HttpServletRequest request,
        @NonNull HttpServletResponse response,
        @NonNull FilterChain filterChain
    )
        throws ServletException, IOException {

        try {
            X509Certificate[] certs = (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate");

            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
                TrustManagerFactory.getDefaultAlgorithm()
            );
            trustManagerFactory.init(keyStore);

            for (TrustManager trustManager : trustManagerFactory.getTrustManagers()) {
                if (trustManager instanceof X509TrustManager x509TrustManager) {
                    x509TrustManager.checkServerTrusted(certs, "RSA");
                }
            }
        } catch (CertificateException | IllegalArgumentException e) {
            log.warn("Invalid certificate: {}", e.getMessage());
            response.sendError(HttpServletResponse.SC_FORBIDDEN, "Invalid certificate");
            return;
        } catch (Exception e) {
            log.error("Error during certificate validation: {}", e.getMessage());
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Error during certificate validation");
            return;
        }

        filterChain.doFilter(request, response);
    }

}

升级 Spring Boot 3 后,请求不包含“javax.servlet.request.X509Certificate”,也不包含“jakarta.servlet.request.X509Certificate”属性(即证书始终为 null)。我是否可以知道如何仅验证特定端点的客户端证书?

java spring-boot tomcat spring-security x509证书

评论

3赞 Andy Wilkinson 11/10/2023
您使用的是哪个 Web 服务器?它应该能够为您执行此操作,而无需您自己的过滤器。
0赞 Anthony Vinay 11/10/2023
@AndyWilkinson我正在使用 Tomcat Web 服务器
1赞 Andy Wilkinson 11/10/2023
您是如何配置 SSL 的?设置将要求客户端提供受信任的证书。您还必须配置信任存储(也有属性),以便 Tomcat 知道要信任哪些证书。server.ssl.client-auth=needserver.ssl.*
1赞 dur 11/12/2023
您用 Spring Security 标记了您的问题,但我没有看到您正在使用 Spring Security。相反,您编写了一些自定义代码。您在使用 Spring Security 吗?如果是,为什么要编写一些自定义代码?
0赞 Anthony Vinay 11/13/2023
@AndyWilkinson在这些属性中,server.ssl.key-store 和 trust.store 我会提到文件的内容(即 .p12 文件的 base64 内容)。有没有办法做到这一点?

答: 暂无答案