我有一个网页,需要Mutual auth才能加载页面。 我使用ERROR_FAILED_SSL_HANDSHAKE获得onReceivedError()。在Webkit中打印日志“无法建立安全连接”。 我已经广泛搜索但找不到答案。有几个帖子但没有结论。 我尝试了here发布的所有3个解决方案。 可能起作用的解决方案是: - 解决方案1: 无论如何都使用ClientCertRequestHandler(它标记为隐藏,但显然仍然可用):
所以我修改了android.jar以包含内部API以覆盖onReceivedClientCertRequest() 但我没有在运行时获得回调。任何第三方浏览器都是如此。我尝试在标准浏览器中加载相同的网页。我在UI上收到一个回调,要求用户选择一个客户端证书。
所以似乎只有系统浏览器应用程序可以从Webkit获取onReceivedClientCertRequest()的回调。
对于iOS平台,Webview也无法直接加载网站。但是使用NSURL进行HTTPS连接, 将客户端证书保留在内存中一段时间,Webview可以成功加载此页面。
在Android上,我通过注册加载客户端和服务器证书的SSLSocketFactory成功设置了HTTPS通信。 我可以使用它进行REST API调用。但是,与iOS不同,我无法找到Android webview可以使用客户端证书进行相互身份验证的方式。
我认为平台应支持在Webview上进行相互认证,这是安全性的基本要求之一。这个问题有没有更新?
编辑1 :
根据我在下面给出的答案,我在Android 4.0到4.3上工作了。 Hoverer,现在在Android 4.4上,似乎WebViewClientClassicExt类本身被删除了。 知道在这种情况下可以做些什么吗?为什么Android不允许在webview中设置ClientCertificates?
答案 0 :(得分:3)
所以我可以让这件事工作到4.3
我设置私钥和证书ClientCertRequestHandler proceed()方法。
Android需要4.4及更高版本的补丁
<强> EDITED 强> 解决方案uptil 4.3如下所示
WebviewClientCustom.java
public class WebViewClientCustom extends WebViewClient {
private X509Certificate[] certificatesChain;
private PrivateKey clientCertPrivateKey;
private IWebViewCallbacks webviewCallbacks;
public WebViewClientCustom(IWebViewCallbacks webviewCallbacks) {
this.webviewCallbacks = webviewCallbacks;
}
public void onReceivedClientCertRequest(WebView paramWebView,
ClientCertRequestHandler paramClientCertRequestHandler,
String paramString) {
PrivateKey localPrivateKey = this.clientCertPrivateKey;
X509Certificate[] arrayOfX509Certificate = this.certificatesChain;
paramClientCertRequestHandler.proceed(localPrivateKey,
arrayOfX509Certificate);
}
public void onReceivedError(WebView view, int errorCode,
String description, String failingUrl) {
webviewCallbacks.onReceivedError( view, errorCode,
description, failingUrl);
super.onReceivedError( view, errorCode,
description, failingUrl);
}
public void setClientCertificate(PrivateKey paramPrivateKey,
X509Certificate[] paramArrayOfX509Certificate) {
this.clientCertPrivateKey = paramPrivateKey;
this.certificatesChain = paramArrayOfX509Certificate;
}
public boolean shouldOverrideUrlLoading(WebView paramWebView,
String paramString) {
return webviewCallbacks.shouldOverrideUrlLoading(paramWebView,
paramString);
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
// TODO Auto-generated method stub
webviewCallbacks.onPageStarted(view, url, favicon);
super.onPageStarted(view, url, favicon);
}
@Override
public void onPageFinished(WebView view, String url) {
// TODO Auto-generated method stub
webviewCallbacks.onPageFinished(view, url);
super.onPageFinished(view, url);
}
}
WebViewClientCustomExt.java
public class WebViewClientCustomExt extends WebViewClientClassicExt {
private X509Certificate[] certificatesChain;
private PrivateKey clientCertPrivateKey;
private IWebViewCallbacks webviewCallbacks;
public WebViewClientCustomExt(IWebViewCallbacks webviewCallbacks) {
this.webviewCallbacks = webviewCallbacks;
}
public void onReceivedClientCertRequest(WebView paramWebView,
ClientCertRequestHandler paramClientCertRequestHandler,
String paramString) {
PrivateKey localPrivateKey = this.clientCertPrivateKey;
X509Certificate[] arrayOfX509Certificate = this.certificatesChain;
paramClientCertRequestHandler.proceed(localPrivateKey,
arrayOfX509Certificate);
}
public void onReceivedError(WebView view, int errorCode,
String description, String failingUrl) {
webviewCallbacks.onReceivedError( view, errorCode,
description, failingUrl);
super.onReceivedError( view, errorCode,
description, failingUrl);
}
public void setClientCertificate(PrivateKey paramPrivateKey,
X509Certificate[] paramArrayOfX509Certificate) {
this.clientCertPrivateKey = paramPrivateKey;
this.certificatesChain = paramArrayOfX509Certificate;
}
public boolean shouldOverrideUrlLoading(WebView paramWebView,
String paramString) {
return webviewCallbacks.shouldOverrideUrlLoading(paramWebView, paramString);
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
// TODO Auto-generated method stub
webviewCallbacks.onPageStarted(view, url, favicon);
super.onPageStarted(view, url, favicon);
}
@Override
public void onPageFinished(WebView view, String url) {
// TODO Auto-generated method stub
webviewCallbacks.onPageFinished(view, url);
super.onPageFinished(view, url);
}
}
用法
*/
private void setCertificateData() {
// TODO Auto-generated method stub
try {
KeyStore clientCertKeystore = KeyStore.getInstance("pkcs12");
String clientCertPkcsPassword = getPkcsPassword();
byte[] pkcs12;
pkcs12 = getAuthP12Data();
ByteArrayInputStream pkcs12BAIS = new ByteArrayInputStream(pkcs12);
clientCertKeystore.load(pkcs12BAIS,
clientCertPkcsPassword.toCharArray());
String alias = (clientCertKeystore.aliases().nextElement());
Certificate[] arrayOfCertificate = clientCertKeystore
.getCertificateChain(alias);
X509Certificate[] arrayOfX509Certificate = new X509Certificate[arrayOfCertificate.length];
for (int i = 0; i < arrayOfCertificate.length; i++) {
arrayOfX509Certificate[i] = (X509Certificate) arrayOfCertificate[i];
}
PrivateKey localPrivateKey = (PrivateKey) clientCertKeystore
.getKey(alias, clientCertPkcsPassword.toCharArray());
if (android.os.Build.VERSION.SDK_INT <= 16) {
WebViewClientCustom webvviewClient = new WebViewClientCustom(
myWebViewClient);
webvviewClient.setClientCertificate(localPrivateKey,
arrayOfX509Certificate);
webView.setWebViewClient(webvviewClient);
} else {
WebViewClientCustomExt webvviewClient = new WebViewClientCustomExt(
myWebViewClient);
webvviewClient.setClientCertificate(localPrivateKey,
arrayOfX509Certificate);
webView.setWebViewClient(webvviewClient);
}
// webView.getSettings().setJavaScriptEnabled(true);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}