【发布时间】:2014-12-25 11:23:41
【问题描述】:
我已经编写了 Spring 控制器。这是来自客户的请求。这只是 REST 风格。
这很好。但我需要证书认证。只有客户端才能访问其余服务(spring 控制器),这些服务具有带密钥的客户端证书(换句话说,客户端应该拥有带密钥的密钥库)。
如何将此安全性配置为 spring?你能给我一个例子或链接吗?
谢谢
【问题讨论】:
标签: java spring rest spring-mvc spring-security
我已经编写了 Spring 控制器。这是来自客户的请求。这只是 REST 风格。
这很好。但我需要证书认证。只有客户端才能访问其余服务(spring 控制器),这些服务具有带密钥的客户端证书(换句话说,客户端应该拥有带密钥的密钥库)。
如何将此安全性配置为 spring?你能给我一个例子或链接吗?
谢谢
【问题讨论】:
标签: java spring rest spring-mvc spring-security
您要查找的内容称为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 应用程序都将使用新更新的信任库。并不总是人们想要的,可能会导致安全风险。
【讨论】:
<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" .../>
我创建了一个 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 注释一样使用它。
【讨论】: