HttpClient支持多种TLS协议

时间:2013-08-14 16:44:50

标签: java spring ssl httpclient apache-commons-httpclient

我们正在编写一个必须使用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不喜欢实例化并自动装配两个HttpClient对象: / p>

SEVERE: Servlet /my-refsvc threw load() exception
java.lang.NullPointerException
at com.company.project.refsvc.base.HttpsClientFactory.<clinit>(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)如果两者都有可能,那么“更好”的做法是什么?

1 个答案:

答案 0 :(得分:4)

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

  

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

     

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

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

有几种可能性:

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

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

      

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