我需要将应用程序与外部Web服务集成,强制使用https。这个Web服务的作者为我提供了.crt文件,我应该用它来发出https请求。经过一些调查后,我发现以下代码使用KeyStore类进行安全的https访问:
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
FileInputStream instream = new FileInputStream(new File(file));
try {
trustStore.load(instream, password.toCharArray());
} finally {
instream.close();
}
SSLContext sslcontext =
SSLContexts.custom().loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()).build();
SSLConnectionSocketFactory sslsf =
new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1.2"}, null,
BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
HttpClients.custom().setSSLSocketFactory(sslsf).build();
在此代码中,KeyStore需要输入流以及密码 trustStore.load(instream, password.toCharArray())
;。但是,据我所知,使用.crt文件时我们不需要密码。所以这种加载证书的方式并不适合我。同时,从我到目前为止发现的,我在这里提供的代码是配置HttpClient使用SSL证书的唯一方法。是否有任何解决方法来配置HttpClient使用.crt证书?
谢谢,
安德烈
答案 0 :(得分:1)
我认为Web服务正在为您提供自签名证书(即未由知名CA签名)。如果它已经由Java的cacerts文件中的知名CA签名,那么您不需要做任何事情。
否则,你有几个选择:
在任何一种情况下,首先需要将crt文件转换为Java使用的jks密钥库。您可以通过以下方式执行此操作:
$ keytool -import -keystore mykeystore.jks -storepass horsestaple
请注意,keytool需要提供密码(上面为horsestaple
)才能创建jks商店。你可以放任何东西;如你所知,公共网站证书不需要密码保护,毕竟它们是公开的。
如果您正在执行选项1,请备份您的cacerts并提供cacerts文件而不是mykeystore.jks。请参阅以下链接,了解cacerts的位置。对于此选项,您已完成设置,您的应用程序应通过HTTPS连接到Web服务而无需任何其他配置,因为Java默认情况下会加载cacerts。
如果您正在执行选项2,这可能是首选,至少在测试阶段,您需要使用此参数运行您的应用程序:
-Djavax.net.ssl.trustStore=mykeystore.jks
这是一个JVM参数,因此请适当提供。这取决于您运行应用程序的方式。
请注意,在这种情况下,您只会拥有导入的证书,因此您的其他HTTPS连接将不起作用。您可以通过先将标准cacerts复制到临时位置,将密钥导入其中并在上面的命令中使用它来避免这种情况。这将为您提供所有标准证书,以及您需要的证书。
选项2的一个小缺点是,如果添加或撤销新证书,则不会更新特定于应用程序的密钥库。如果这是一个问题,您可以动态合并密钥库,例如:
在任何一种情况下,您现在都应该只能进行标准的URL提取,例如此处给出的示例:
即:
final URL url = new URL("https://example.com");
try(final InputStream in = url.openStream()){
//…
}
此处提供更多信息:
https://docs.oracle.com/cd/E19830-01/819-4712/ablqw/index.html
http://docs.oracle.com/javase/7/docs/technotes/tools/solaris/keytool.html
希望这有帮助。
答案 1 :(得分:0)
除非他们为您提供他们的 .crt文件,该文件应该用于验证连接到他们,这表明他们正在使用自签名证书,他们没有为您提供任何有用的东西。如果您需要证书作为客户端,那么您需要的第一件事就是公钥/私钥对,您可以从中生成CSR,您将对其进行签名。除签名证书外,没有其他人可以安全地提供任何其他内容。
如果他们提供了自己的(自签名?)证书,则需要通过keytool
将{{1>}加载到 truststore 而不是密钥库中然后告诉Java使用该信任库,通过-trustcacerts
系统属性或构建自己的javax.net.ssl.trustStore
并将其提供给自定义TrustManager
,如JSSE中所述参考指南。