【问题标题】:SSL requests failing in production onlySSL 请求仅在生产中失败
【发布时间】:2016-12-19 10:09:43
【问题描述】:

我在运行 Java 7 (Oracle JVM) 的 Tomcat 7 上部署了一个 Java webapp。

我对外部 HTTPS url 的所有 Apache HTTPClient 请求都失败了(仅在生产中),我不太清楚为什么。我检查了JVM自带的cacerts信任库,所有证书都是有效的。

我已将 JVM 和 Tomcat 目录下载到我的开发机器并运行了 webapp(使用相同的路径、相同的参数等)并且它可以工作。

执行在生产环境中发出 HTTPS 请求的独立 JAR 也可以。

坦率地说,在这一点上,我没有想法。

这是失败的示例代码:

  InputStream is=null;

  HttpParams httpParams = new BasicHttpParams();
  HttpConnectionParams.setConnectionTimeout(httpParams, 2000);
  HttpConnectionParams.setSoTimeout(httpParams, 2000);

  DefaultHttpClient httpclient = new DefaultHttpClient(httpParams);
  try {
      httpclient.getParams().setParameter("http.useragent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
      HttpContext localContext = new BasicHttpContext();

      HttpHead httphead = new HttpHead(url); 
      HttpResponse response = httpclient.execute(httphead, localContext);

      HttpGet httpget = new HttpGet(url); 
      response = httpclient.execute(httpget, localContext);

      HttpEntity entity = response.getEntity();
      is= new ByteArrayInputStream(EntityUtils.toByteArray(entity));

  } catch (IOException ie) {
      throw new IOException("IO exception",ie);
  } finally {
      httpclient.getConnectionManager().shutdown();
  }
  return is;

堆栈跟踪示例:

Caused by: javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
        at sun.security.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:421)
        at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:128)
        at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:390)
        at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:148)
        at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:149)
        at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:121)
        at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:561)
        at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:415)
        at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:820)
        at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:754)

Tomcat JAVA_OPTS:

JAVA_OPTS="-server -Xms4g -Xmx4g -XX:PermSize=512m -XX:MaxPermSize=512m -XX:+UseConcMarkSweepGC -XX:+DisableExplicitGC -Dfile.encoding=UTF-8 -Djavax.net.ssl.trustStore=/usr/lib/jvm/java-7-oracle/jre/lib/security/cacerts -Djavax.net.ssl.trustStorePassword=changeit"

【问题讨论】:

  • 您应该使用来自实际生产服务器的一些 CLI 工具检查您访问的任何 URL 的 SSL 证书,并检查此证书是否与您在本地获得的证书相匹配,例如使用您的浏览器。有关您的一些选择,请参阅this question。也许有一些代理可以终止远程 SSL?!
  • @dpr 谢谢,遗憾的是他们匹配。我正在连接知名服务,例如 imgur 或 mailgun。

标签: java ssl httpclient


【解决方案1】:

如果不访问您的环境,很难判断。我要检查的第一件事:

  • 确保您确实在使用您认为正在使用的 JVM 和信任存储
  • 检查用户主目录中的 .ssh 目录。
  • 您是否有任何在本地运行的 ssl 工具,例如 plink?
  • 您是否设置了任何与 SSL 相关的环境变量?
  • 生产服务器上的防火墙设置是什么?

【讨论】:

  • 1.我确实通过运行 ps aux | 检查了我是否运行了正确的 JVM。 grep 爪哇。 2. 为什么要查看 .ssh 目录? 3. 我没有运行任何 ssl 工具。 4. Tomcat 在 www-data 用户下运行,这里是环境变量:pastie.org/10983959 5. iptables: OUTPUT ACCEPT pastie.org/10983960
  • 唯一改变的是我将站点从 HTTP 切换到 HTTPS,但我通过配置 Cloudflare 做到了这一点。我自己的 nginx 和 tomcat 在 HTTP 上运行。
【解决方案2】:

你需要配置 https 的 8443 端口 请参阅以下链接了解更多详情 https://www.mkyong.com/tomcat/how-to-configure-tomcat-to-support-ssl-or-https/

【讨论】:

  • Tomcat 在 HTTP 上运行。 SSL 终止在 Cloudflare 上完成。
【解决方案3】:

事实证明,与 Oracle Java 捆绑在一起的 cacerts 文件中的证书不包含我向其发送请求的网站的根证书。我用 OpenJDK 包中的 cacerts 文件替换了该文件,一切都恢复正常了。

【讨论】:

    猜你喜欢
    • 2018-05-15
    • 1970-01-01
    • 2019-10-23
    • 2019-10-05
    • 2011-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-10
    相关资源
    最近更新 更多