HttpClient支持多种TLS协议

我们正在编写一个必须使用HTTPS与几台服务器通信的应用程序。 它需要与AWS(使用AWS库)以及使用TLS 1.2的一些内部服务进行通信。

我开始通过更改我的HttpClient来使用TLS 1.2 SSLContext:

public static SchemeRegistry buildSchemeRegistry() throws Exception { final SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); sslContext.init(createKeyManager(), createTrustManager(), new SecureRandom()); final SchemeRegistry schemeRegistry = new SchemeRegistry(); schemeRegistry.register(new Scheme("https", 443, new SSLSocketFactory(sslContext))); return schemeRegistry; } 

并将此SchemeRegistry注入到DefaultHttpClient对象中(通过spring),但这样做我从AWS得到错误,因此我假设(我可能错了)AWS不支持TLS 1.2(如果我只是,我不会收到此消息使用正常的DefaultHttpClient):

 AmazonServiceException: Status Code: 403, AWS Service: AmazonSimpleDB, AWS Request ID: 5d91d65f-7158-91b6-431d-56e1c76a844c, AWS Error Code: InvalidClientTokenId, AWS Error Message: The AWS Access Key Id you provided does not exist in our records. 

如果我尝试在spring中定义两个HttpClient,一个使用TLS 1.2,一个是默认值,我得到以下错误,我认为这意味着Spring不喜欢实例化并自动assembly两个HttpClient对象:

 SEVERE: Servlet /my-refsvc threw load() exception java.lang.NullPointerException at com.company.project.refsvc.base.HttpsClientFactory.(BentoHttpsClientFactory.java:25) ... org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1031) at ... org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223) 

我没有在Java中使用过多的HTTPS,所以请问有什么人给我一些建议吗? 1)我如何让Spring允许两个HttpClient对象,一个连接到AWS东西bean,另一个连接到其他bean以访问TLS1.2服务2)或者是否可以更改一个HttpClient对象能够尝试TLS1.2(通过SSLContext,或SchemeRegistry或其他东西),如果失败,那么尝试TLS1.1或1.0? 3)如果两者都有可能,那么“更好”的做法是什么?

TLS有一个内置机制来协商使用哪个版本的协议。 来自RFC 5246(附录E) :

TLS版本1.0,1.1和1.2以及SSL 3.0非常相似,并使用兼容的ClientHello消息; 因此,支持所有这些相对容易。 同样,只要ClientHello格式保持兼容,服务器就可以轻松处理尝试使用未来版本TLS的客户端,并且客户端支持服务器中可用的最高协议版本。

希望与这些旧服务器协商的TLS 1.2客户端将在ClientHello.client_version中发送包含{3,3}(TLS 1.2)的普通TLS 1.2 ClientHello。 如果服务器不支持此版本,它将使用包含旧版本号的ServerHello进行响应。 如果客户同意使用此版本,则协商将根据协商协议进行。

此外,更改SSLContext.getInstance(...)的版本号仅会更改默认启用协议。 使用SSLSocket.setEnabledProtocols(...)设置实际协议版本(请参阅此问题 )。 我不确定你正在使用的其他库,但它可能会在某处设置启用的协议。

有几种可能性:

  • 您在createKeyManager()所做的事情与默认行为不同。 如果服务使用客户端证书身份validation,配置错误肯定会导致403错误。

  • (不太可能,我猜,但很难说没有看到你的createKeyManager()createTrustManager() )。 您使用的服务器可能与TLS 1.2和版本协商机制不兼容。 sun.security.ssl.SSLContextImpl有此评论:

    SSL / TLS协议指定了前向兼容性和版本回滚攻击保护,但是,许多SSL / TLS服务器供应商没有正确实现这些方面,并且一些当前的SSL / TLS服务器可能拒绝与TLS 1.1或更高版本通信客户。