Java Android HttpClient - 证书中的主机名与 <example.com> != <*.example.com> 不匹配
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3135679/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Android HttpClient - hostname in certificate didn't match <example.com> != <*.example.com>
提问by noah
I'm using HttpClient on Android to connect to https://someUrl.com/somePath. The problem is that the site's certificate is for *.someUrl.com, not someUrl.com, so I get an SSLException. Lame on the part of the site, yes, but unless I can get it fixed, I'm stuck. Is there a way I can get HttpClient to relax and accept the certificate?
我在 Android 上使用 HttpClient 连接到https://someUrl.com/somePath。问题是该站点的证书用于 *.someUrl.com,而不是 someUrl.com,因此我收到 SSLException。网站的部分蹩脚,是的,但除非我能修复它,否则我被卡住了。有没有办法让 HttpClient 放松并接受证书?
采纳答案by noah
This is my (edited) solution:
这是我的(编辑过的)解决方案:
class MyVerifier extends AbstractVerifier {
private final X509HostnameVerifier delegate;
public MyVerifier(final X509HostnameVerifier delegate) {
this.delegate = delegate;
}
@Override
public void verify(String host, String[] cns, String[] subjectAlts)
throws SSLException {
boolean ok = false;
try {
delegate.verify(host, cns, subjectAlts);
} catch (SSLException e) {
for (String cn : cns) {
if (cn.startsWith("*.")) {
try {
delegate.verify(host, new String[] {
cn.substring(2) }, subjectAlts);
ok = true;
} catch (Exception e1) { }
}
}
if(!ok) throw e;
}
}
}
public DefaultHttpClient getTolerantClient() {
DefaultHttpClient client = new DefaultHttpClient();
SSLSocketFactory sslSocketFactory = (SSLSocketFactory) client
.getConnectionManager().getSchemeRegistry().getScheme("https")
.getSocketFactory();
final X509HostnameVerifier delegate = sslSocketFactory.getHostnameVerifier();
if(!(delegate instanceof MyVerifier)) {
sslSocketFactory.setHostnameVerifier(new MyVerifier(delegate));
}
return client;
}
It has the advantage of not changing the default behavior unless there is a wildcard domain, and in that case it revalidates as though the 2 part domain (e.g., someUrl.com) were part of the certificate, otherwise the original exception is rethrown. That means truly invalid certs will still fail.
它的优点是除非存在通配符域,否则不会更改默认行为,在这种情况下,它会重新验证,就好像 2 部分域(例如 someUrl.com)是证书的一部分一样,否则将重新抛出原始异常。这意味着真正无效的证书仍然会失败。
回答by Melody Horn
If it wants *.someUrl.com
, then it seems like you could just give it www.someUrl.com/somePath
instead of someUrl.com/somePath
.
如果它想要*.someUrl.com
,那么您似乎可以只给它www.someUrl.com/somePath
而不是someUrl.com/somePath
.
回答by ZZ Coder
The BouncyCastle on Android is too old and it doesn't recognize wildcard certificate.
Android 上的 BouncyCastle 太旧,无法识别通配符证书。
You can write your own X509TrustManager to check for wildcard.
您可以编写自己的 X509TrustManager 来检查通配符。
or you can disable certificate check altogether if you can accept the risk. See this question,
或者,如果您可以接受风险,则可以完全禁用证书检查。看到这个问题,
回答by Ayreon
if you use a WebView just call
如果您使用 WebView 只需调用
webview.clearSslPreferences();
to ignore SSL errors
忽略 SSL 错误