HttpClient支持多种TLS协议

age*_*nzo 5 java ssl spring 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;
}
Run Code Online (Sandbox Code Playgroud)

并将此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.
Run Code Online (Sandbox Code Playgroud)

如果我尝试在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)
Run Code Online (Sandbox Code Playgroud)

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

Bru*_*uno 5

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

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

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

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

有几种可能:

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

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

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