简体   繁体   English

HttpClient支持多种TLS协议

[英]HttpClient supporting multiple TLS protocols

We're writing an app that must communicate with a few servers using HTTPS. 我们正在编写一个必须使用HTTPS与几台服务器通信的应用程序。 It needs to communicate with AWS (using the AWS libraries) and also with some of our internal services that use TLS 1.2. 它需要与AWS(使用AWS库)以及使用TLS 1.2的一些内部服务进行通信。

I started off by changing my HttpClient to use a TLS 1.2 SSLContext: 我开始通过更改我的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;
}

and injecting this SchemeRegistry into the DefaultHttpClient object (via spring), but doing that I get errors from AWS and so I assume (I may be wrong) that AWS doesn't support TLS 1.2 (I don't get this message if I just use the normal DefaultHttpClient): 并将此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.

If I try to have two HttpClients defined in spring, one that uses TLS 1.2 and one that is the default, I get the following error, which I assume means that Spring doesn't like instantiating and autowiring two HttpClient objects: 如果我尝试在spring中定义两个HttpClient,一个使用TLS 1.2,一个是默认值,我得到以下错误,我认为这意味着Spring不喜欢实例化并自动装配两个HttpClient对象:

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)

I haven't used HTTPS much in java so could you kind people give me some advice please? 我没有在java中使用过多的HTTPS,所以请问有什么人给我一些建议吗? 1) How would I get Spring to allow two HttpClient objects and for one to be wired to the AWS stuff beans and the other to be wired to the other beans for accessing the TLS1.2 services 2) Or is it possible to change the one HttpClient object to be able to try TLS1.2 (via SSLContext, or the SchemeRegistry or something) and if that fails then try TLS1.1 or 1.0? 1)我如何让Spring允许两个HttpClient对象,一个连接到AWS东西bean,另一个连接到其他bean以访问TLS1.2服务2)或者是否可以更改一个HttpClient对象能够尝试TLS1.2(通过SSLContext,或SchemeRegistry或其他东西),如果失败,那么尝试TLS1.1或1.0? 3) If both are possible, what would be the 'better' way of doing it? 3)如果两者都有可能,那么“更好”的做法是什么?

TLS has an in-built mechanism to negotiate which version of the protocol is to be used. TLS有一个内置机制来协商使用哪个版本的协议。 From RFC 5246 (Appendix E) : 来自RFC 5246(附录E)

TLS versions 1.0, 1.1, and 1.2, and SSL 3.0 are very similar, and use compatible ClientHello messages; TLS版本1.0,1.1和1.2以及SSL 3.0非常相似,并使用兼容的ClientHello消息; thus, supporting all of them is relatively easy. 因此,支持所有这些相对容易。 Similarly, servers can easily handle clients trying to use future versions of TLS as long as the ClientHello format remains compatible, and the client supports the highest protocol version available in the server. 同样,只要ClientHello格式保持兼容,服务器就可以轻松处理尝试使用未来版本TLS的客户端,并且客户端支持服务器中可用的最高协议版本。

A TLS 1.2 client who wishes to negotiate with such older servers will send a normal TLS 1.2 ClientHello, containing { 3, 3 } (TLS 1.2) in ClientHello.client_version. 希望与此类旧服务器协商的TLS 1.2客户端将在ClientHello.client_version中发送包含{3,3}(TLS 1.2)的普通TLS 1.2 ClientHello。 If the server does not support this version, it will respond with a ServerHello containing an older version number. 如果服务器不支持此版本,它将使用包含旧版本号的ServerHello进行响应。 If the client agrees to use this version, the negotiation will proceed as appropriate for the negotiated protocol. 如果客户同意使用此版本,则协商将根据协商协议进行。

In addition, changing the version number in SSLContext.getInstance(...) only changes which protocols are enabled by default . 此外,更改SSLContext.getInstance(...)的版本号仅会更改默认情况下启用协议。 Setting the actual protocol versions is done with SSLSocket.setEnabledProtocols(...) (see this question ). 使用SSLSocket.setEnabledProtocols(...)设置实际协议版本(请参阅此问题 )。 I'm not sure about the rest of the libraries you're using, but it's possible that it sets the enabled protocols somewhere. 我不确定你正在使用的其他库,但它可能会在某处设置启用的协议。

There are a few possibilities: 有几种可能性:

  • What you're doing in your createKeyManager() differs from the default behaviour. 您在createKeyManager()所做的事情与默认行为不同。 If the service is using client-certificate authentication, bad configuration there would certainly lead to a 403 error. 如果服务使用客户端证书身份验证,配置错误肯定会导致403错误。

  • (Less likely, I guess, but hard to say without seeing your createKeyManager() and createTrustManager() ). (不太可能,我猜,但很难说没有看到你的createKeyManager()createTrustManager() )。 Perhaps the server you're using isn't compatible with TLS 1.2 and the version negotiation mechanism. 您使用的服务器可能与TLS 1.2和版本协商机制不兼容。 There is this comment in sun.security.ssl.SSLContextImpl : sun.security.ssl.SSLContextImpl有此评论:

    SSL/TLS protocols specify the forward compatibility and version roll-back attack protections, however, a number of SSL/TLS server vendors did not implement these aspects properly, and some current SSL/TLS servers may refuse to talk to a TLS 1.1 or later client. SSL / TLS协议指定了前向兼容性和版本回滚攻击保护,但是,许多SSL / TLS服务器供应商没有正确实现这些方面,并且一些当前的SSL / TLS服务器可能拒绝与TLS 1.1或更高版本通信客户。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM