【问题标题】:Spring REST Service Certificate authSpring REST 服务证书身份验证
【发布时间】:2014-12-25 11:23:41
【问题描述】:

我已经编写了 Spring 控制器。这是来自客户的请求。这只是 REST 风格。

这很好。但我需要证书认证。只有客户端才能访问其余服务(spring 控制器),这些服务具有带密钥的客户端证书(换句话说,客户端应该拥有带密钥的密钥库)。

如何将此安全性配置为 spring?你能给我一个例子或链接吗?

谢谢

【问题讨论】:

    标签: java spring rest spring-mvc spring-security


    【解决方案1】:

    您要查找的内容称为Mutual Authentication

    服务器负责制作/请求客户端发送其证书。每个服务器执行此操作的方式不同,您必须查看如何配置您的特定服务器。

    对于 Spring Security,我建议查看 X.509 Authentication。这种类型的身份验证相当容易使用,并且可以根据需要进行扩展。

    编辑

    因此,这里有一些参考资料可以说明您所问的问题:

    http://whiteycode.blogspot.com/2012/04/part-3-x509-authentication-with-spring.html

    PDF 警告

    http://www.promixis.com/pdfs/SpringSecurityAndX509ClientCertificates.pdf

    上面的pdf文件已经无法访问了……

    这个例子很好地解释了如何设置您的证书和创建您自己的个人 CA(证书颁发机构)。警告,他们展示制作客户证书的方式只是一种方式,而不是方式。您的客户端(IE Web 浏览器或 java httpclient 客户端)应确定创建客户端证书的方式。 Java 当然喜欢使用它的 java 密钥库,而浏览器往往喜欢 p12 样式的证书。

    最终建议/警告...我不知道您对证书的了解程度,但是...相互身份验证就是关于谁信任谁。有责任说,我需要你用证书来验证自己,这里是我信任的证书提供者的列表。然后,客户端负责回复由这些服务器受信任的证书提供商之一签名的证书。应用程序有责任说,我是否根据证书中的姓名信任此人?当事情开始出错时,想想谁在信任谁,谁不信任谁。

    一个很棒的工具是在您的应用程序上使用 -Djavax.net.debug=ssl。它将显示整个 ssl 握手以及请求的内容以及具体的响应是什么。该选项有点冗长,但在需要时使用它很不错。

    编辑 X 2

    这是在 Tomcat 7 上启用相互身份验证的方法。

    在您的 server.xml 配置文件中,您应该看到接近以下内容的 SSL 连接器:

    <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
               maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
               clientAuth="want" sslProtocol="TLS"
               keystoreFile="C:\Java\Certs\localhost.jks"
               keystorePass="changeit"
               URIEncoding="UTF-8" />
    

    需要注意的重要值是 clientAuth 值。

    将 clientAuth 设置为“想要”告诉客户端从服务器信任的证书列表中发送签名的客户端 ssl 证书(如果有的话)。如果没有,请照常提出您的请求。

    将 clientAuth 设置为“true”告诉客户端他们必须从服务器信任的证书列表中发送签名的客户端 ssl 证书。如果您没有由服务器信任的证书列表签名的证书,则不允许客户端发出请求。

    服务器信任的证书列表要么来自默认的 java 信任库,要么可以使用 -Djavax.net.ssl.trustStore="C:\Java\Certs\jssecacerts1" VM 选项设置。

    通常,当您信任的特定 CA 证书不在默认 Java 信任库中时,会复制默认信任库,将新 CA 证书导入到复制的信任库中,然后与上述 VM 选项一起使用。

    警告

    不要更改默认的 Java 信任库,这一点非常重要。如果这样做,默认情况下该机器上的所有 Java 应用程序都将使用新更新的信任库。并不总是人们想要的,可能会导致安全风险。

    【讨论】:

    • 是的,我想向 Spring 控制器(接收 REST 样式请求)提供 X.509 身份验证的示例。你能再给我一个参考,所有的东西都会从里到外展开吗?
    • 哇,这是一个艰巨的任务。我会四处搜索,看看是否有类似的东西并更新答案。
    • 正如您告诉我的“这是服务器的责任”。如果它是在服务器端完成的(例如我们可以在 tomcat 中完成),为什么 spring security 有 X.509 身份验证?
    • 我想你把我的句子断章取义了。我说“服务器负责制作/请求客户端发送其证书。”这句话意味着需要设置tomcat进行所谓的相互认证。在连接器的 server.xml 中,参数 clientAuth 必须设置为 want 或 true。然后,Tomcat 会将证书信息传递给 spring,然后 spring 将确定是否应该对请求进行身份验证。我已经更新了答案以提供一个链接,该链接解释了如何使用相互身份验证配置 tomcat。
    • truststore 也是必需的(至少 Tomcat 8 需要它,不确定其他版本)。我的配置:&lt;Connector clientAuth="true" keystoreFile="/data/keystore" keystorePass="123456" truststoreFile="/data/keystore" truststorePass="123456" port="8443" protocol="HTTP/1.1" scheme="https" secure="true" sslProtocol="TLS" .../&gt;
    【解决方案2】:

    我创建了一个 100% 可理解的示例项目,其中包含设置 Spring Boot 应用所需的一切,该应用具有受客户端证书保护的 REST 端点 - 以及配置为使用与安全服务器通信的客户端证书:https://github.com/jonashackt/spring-boot-rest-clientcertificate

    它还包含生成.key.crt.jks 文件所需的所有 步骤。如果您不想使用自签名证书,只需相应地调整步骤即可。

    RestTemplate 是这样配置的:

    package de.jonashackt.restexamples;
    
    import org.apache.http.client.HttpClient;
    import org.apache.http.impl.client.HttpClients;
    import org.apache.http.ssl.SSLContextBuilder;
    import org.springframework.boot.web.client.RestTemplateBuilder;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
    import org.springframework.util.ResourceUtils;
    import org.springframework.web.client.RestTemplate;
    
    import javax.net.ssl.SSLContext;
    
    @Configuration
    public class RestClientCertTestConfiguration {
    
        private String allPassword = "allpassword";
    
        @Bean
        public RestTemplate restTemplate(RestTemplateBuilder builder) throws Exception {
    
            SSLContext sslContext = SSLContextBuilder
                    .create()
                    .loadKeyMaterial(ResourceUtils.getFile("classpath:keystore.jks"), allPassword.toCharArray(), allPassword.toCharArray())
                    .loadTrustMaterial(ResourceUtils.getFile("classpath:truststore.jks"), allPassword.toCharArray())
                    .build();
    
            HttpClient client = HttpClients.custom()
                    .setSSLContext(sslContext)
                    .build();
    
            return builder
                    .requestFactory(new HttpComponentsClientHttpRequestFactory(client))
                    .build();
        }
    }
    

    然后,您可以像习惯使用 Test.class 中的 @Autowired 注释一样使用它。

    【讨论】:

      猜你喜欢
      • 2015-03-19
      • 1970-01-01
      • 2019-07-30
      • 2014-07-10
      • 2013-06-22
      • 2013-11-12
      • 2020-06-24
      • 2011-08-16
      • 2018-03-28
      相关资源
      最近更新 更多