为啥android会得到错误的ssl证书? (两个域,一台服务器)

Posted

技术标签:

【中文标题】为啥android会得到错误的ssl证书? (两个域,一台服务器)【英文标题】:Why does android get the wrong ssl certificate? (two domains, one server)为什么android会得到错误的ssl证书? (两个域,一台服务器) 【发布时间】:2014-03-24 06:43:09 【问题描述】:

我有两个域:foo.netbar.com。它们都有 SSL 证书,并且在所有桌面和移动浏览器中都能正常工作。它们托管在使用 nginx 配置的同一台服务器上。

但是,当我从本机 android 应用程序中向域发出请求时,它会以某种方式从错误的域中获取证书!这会导致 IO 异常:

request = new HttpPost("https://foo.net/api/v1/baz");
request.setHeader("Authorization", "user:pass");
response = httpClient.execute(request);

...

javax.net.ssl.SSLException: hostname in certificate didn't match: <foo.net> != <bar.com> OR <bar.com> OR <www.bar.com>

当所有其他措施似乎都表明服务器配置正确时,什么会导致 android/java 尝试使用来自 bar.com 的证书? nginx 访问或错误日志中没有出现任何内容。在我的 android 项目中的任何地方都没有提到 bar.com

编辑:我不知道为什么,但似乎服务器正在使用服务器 IP bar.com 的证书https://198.245.xx.xxx

【问题讨论】:

【参考方案1】:

此问题最可能的原因是服务器使用Server Name Indication 来选择要发送的证书。如果客户端不支持 SNI,则服务器无法选择在 SSL/TLS 握手期间(在发送任何 HTTP 流量之前)发送哪个证书。当您想在同一个 IP 地址和端口上使用多个证书时需要 SNI,但并非所有客户端都支持它(众所周知,任何版本的 Windows XP 上的 IE 和许多移动浏览器)。

您还明显地使用了 Apache HTTP 客户端库(不是 HttpsURLConnection,there can be SNI support with some Android versions。 在 Apache HTTP 客户端库 is quite recent 中对 SNI 的支持,当然还没有进入 Android 堆栈。

您可能会发现the workaround described in this article 很有用(尽管它似乎只适用于 Android 4.2+)。

另外两个选项是:

为每个主机使用不同的 IP 地址(这样就不需要 SNI),如果您可以控制服务器,或者 使用另一个 HTTP 客户端库(例如HttpsURLConnection)。

【讨论】:

【参考方案2】:

Apache 的解决方案,更像是一个技巧: SSL 证书是根据 /etc/apache2/sites-enabled 中的虚拟主机名加载的。因此,为了欺骗检查,请确保首先加载有问题的证书(请记住,虚拟主机是按名称加载的)。

【讨论】:

没有太多希望,因为我无法在有限的时间内执行上述答案所建议的更改。你的建议是拯救这一天的最后一颗子弹,它确实做到了。总有一天我会请你喝一杯!【参考方案3】:

foo.net 的证书似乎配置错​​误,并且使用与 bar.com 相同的主机名

尝试运行在线证书验证工具,例如 foo.net 上的 https://www.digicert.com/help/,以确保安全。

我认为您需要使用正确的主机名重新生成 foo.net 的证书,或者重新配置 ngix 以确保 nginx 为正确的主机提供正确的证书。

【讨论】:

digicert 帮助工具在两个域中都显示为绿色。 “恭喜!此证书已正确安装。”

以上是关于为啥android会得到错误的ssl证书? (两个域,一台服务器)的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的SSL证书验证失败

为啥更换ssl证书后http访问不了网站?

网站为啥需要安装SSL安全证书?

为啥 Ruby 无法验证 SSL 证书?

Android手机上的SSL连接错误怎么解决?

为啥 python SSL 模块无法验证 graph.facebook.com 证书?