使用Java API的S3 / AWS的SSL问题:“证书中的主机名不匹配”

亚马逊在1.3.21版本的AWS Java SDK中“升级”了SSL安全性。 在使用Amazon的AWS Java API时,这会破坏访问其名称中具有句点的任何S3存储桶。 我使用的是版本1.3.21.1,目前是2012年10月5日。 我在下面的回答中提供了一些解决方案,但我正在寻找针对此问题的其他解决方法。

如果您收到此错误,您将在例外/日志中看到类似以下消息的内容。 在此示例中,存储桶名称为foo.example.com

 INFO: Unable to execute HTTP request: hostname in certificate didn't match:  !=  OR  OR  at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:220) at org.apache.http.conn.ssl.StrictHostnameVerifier.verify(StrictHostnameVerifier.java:61) at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:149) at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:130) at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:390) 

您可以在AWS S3论坛上查看此问题的文档:

https://forums.aws.amazon.com/thread.jspa?messageID=387508&#387508

亚马逊对此问题的回应如下。

对于具有此命名模式的存储桶,我们应该能够通过使用旧的路径样式方法来解决此问题(而不是较新的虚拟主机样式寻址)。 我们将开始修复并确保我们的内部集成测试具有包含句点的存储桶名称的测试用例。

任何变通方法或其他解决方案? 感谢您的任何反馈。

事实certificate,亚马逊在2012年9月底“升级”了S3上的SSL安全性。这打破了使用亚马逊AWS Java API时在其名称中有句号的任何S3存储桶的访问。

这是不准确的。 S3的SSL通配符匹配与2006年S3推出时相同。更有可能的是,AWS Java SDK团队对SSL证书进行了更严格的validation(好),但最终破坏了与S3的SSL相冲突的存储桶名称证书(坏)。

正确的答案是您需要使用路径样式寻址而不是DNS样式寻址。 这是解决SSL证书上通配符匹配问题的唯一安全方法。 禁用validation会让您受到中间人攻击。

我目前不知道的是Java SDK是否将其作为可配置选项提供。 如果是这样,那就是你的答案。 否则,听起来像Java SDK团队说“我们将添加此function,然后添加集成测试以确保一切正常。”

亚马逊发布了1.3.22版,解决了这个问题。 我已经validation我们的代码现在可以运行了。 引用他们的发行说明:

现在,可以通过HTTPS再次正确地处理名称包含句点的存储桶。

除了等到亚马逊发布新API之外,我还能看到几种解决方案。

  1. 显然,您可以回滚到1.3.20版本的AWS Java SDK。 不幸的是,我需要1.3.21中的一些function。

  2. 您可以在类路径中替换org.apache.http.conn.ssl.StrictHostnameVerifier 。 这是一个hack但是我会想删除所有对Apache http连接的SSL检查。 这是适用于我的代码: http : //pastebin.com/bvFELdJE

  3. 我最终从AWS源jar下载并构建了自己的包。 我将以下近似补丁应用于HttpClientFactory源。

     =================================================================== --- src/main/java/com/amazonaws/http/HttpClientFactory.java (thirdparty/aws) (revision 20105) +++ src/main/java/com/amazonaws/http/HttpClientFactory.java (thirdparty/aws) (working copy) @@ -93,7 +93,7 @@ SSLSocketFactory sf = new SSLSocketFactory( SSLContext.getDefault(), - SSLSocketFactory.STRICT_HOSTNAME_VERIFIER); + SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); 
  4. 正确的解决方法是从域名桶处理更改为基于路径的处理。

顺便说一下,以下看起来似乎可能有效,但事实并非如此 。 AWS客户端专门请求STRICTvalidation程序,不使用默认validation程序:

 SSLSocketFactory.getSystemSocketFactory().setHostnameVerifier( SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);