最近碰到一个问题, 有朋友问android这边能不能拿到服务器下发的证书,意思就是 自签名证书的https接口,在请求的时候,也没有添加自签名证书进信任列表,直接去发https请求,按照正常https步骤去理解,服务器会返回一个证书,这个证书由于客户端没有添加进信任列表,会导致https请求失败,提示没有找到信任的证书。 朋友疑问: 在服务器返回证书的时候,能不能强行信任呢?
针对这个问题, 我在这边做了测试:
1,由ca签发的ssl证书,部署一个服务
不设置请求的SSLSocketFactory,直接进行https请求
验证结果:ok
2,自签名的ssl证书,部署一个服务
不设置请求的SSLSocketFactory,直接进行https请求
验证结果:error,报错信息 java.security.cert.CertPathValidatorException: Trust anchor for certification path not found,大体意思是没有找打信任的证书,也就是说这个证书没有被当前的请求对象所信任。
看报错信息是android系统已经封装好的证书校验规则。
但是如果不想本地预埋自签名证书,也不想让后台暴露证书下载的接口,该怎么办呢?
我这边提供一个比较简陋的方法,通过webview访问目标https地址,通过webview的onReceivedSslError方法,拿到SslError中的SslCertificate,然后再根据SslCertificate中的saveState方法获取Bundle,从bundle中拿到"x509-certificate"的字节数组,作为字节流读取流,通过通用的httpsutils,设置请求对象的sslsocketfactory。
代码如下:
package com.example.ajaxhttpsdemo;
import android.content.Context;
import android.net.http.SslCertificate;
import android.net.http.SslError;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.webkit.SslErrorHandler;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSu