android主要的通信方式是http和https,但是为了加强安全性,比较建议采用https。
目前HttpClient建议不要再使用了,因为在高版本的android系统中逐渐废弃这种apache的api,转而采用原生的HttpURLConnection方式
那么如何保证https通信安全呢,默认方式下https是信任所有证书的,因此容易受到中间人攻击,所以需要添加证书校验这一环节,下面主要介绍添加证书的两种方式:
1、自定义证书
这种方式允许开发人员用自签的证书来进行https通信,首先是要继承SSLSocketFactory
public class MySSLSocketFactory extends SSLSocketFactory {
SSLContext context = SSLContext.getInstance("TLS");
public UnifiedSSLSocketFactory(KeyStore truststore)
throws NoSuchAlgorithmException, KeyManagementException,
KeyStoreException, UnrecoverableKeyException {
super(truststore);
MyTrustManager tm = new MyTrustManager(truststore);
context.init(null, new TrustManager[]{tm}, new SecureRandom());
}
@Override
public Socket createSocket() throws IOException {
return context.getSocketFactory().createSocket();
}
@Override
public Socket createSocket(Socket socket, String host, int port,
boolean autoClose) throws IOException, UnknownHostException {
return context.getSocketFactory().createSocket(socket, host, port, autoClose);
}
}
然后实现X509TrustManager:
public class MyTrustManager implements X509TrustManager {
private X509TrustManager localTrustManager;
public UnifiedTrustManager(KeyStore localKeyStore) throws KeyStoreException {
try {
this.localTrustManager = createTrustManager(localKeyStore);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
private X509TrustManager createTrustManager(KeyStore store) throws NoSuchAlgorithmException, KeyStoreException {
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init((KeyStore) store);
TrustManager[] trustManagers = tmf.getTrustManagers();
return (X509TrustManager) trustManagers[0];
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
localTrustManager.checkServerTrusted(chain, authType);
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
X509Certificate[] result = localTrustManager.getAcceptedIssuers();
return result;
}
}
其中关于keystore的获取方式是将自签的证书放进自定目录下,然后进行下面的处理:
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
...
FileInputStream in = new FileInputStream(file);//这里的file就是你的自签证书
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
trustStore.setCertificateEntry("ca", certificateFactory.generateCertificate(in));
经过上面的步骤就能创建你自定义的SSLSocketFactory ,最后一个步骤就是使用这个SSLSocketFactory 了,如下:
HttpsURLConnection con = (HttpURLConnection) requestURL.openConneciton();
con.setSSLSocketFactory(mySSLSocketFactory);
2、上传证书到系统
有时候连接只信任系统证书,比如用WebView的时候,因此这时候你需要把你的证书上传到系统目录下才有效果,具体方法如下:
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
Intent intent = KeyChain.createInstallIntent();
Certificate cert = SSLUtil.getCert(context);
if(null != cert) {
try {
intent.putExtra(KeyChain.EXTRA_CERTIFICATE,cert.getEncoded());
intent.putExtra(KeyChain.EXTRA_NAME, "ca");
startActivityForResult(intent, REQUEST_CODE_INSTALL_CERT_TO_SYS);
} catch (CertificateEncodingException e) {
e.printStackTrace();
}
}
}
if里面的判断是因为在API低于4.0的android系统是不支持将自定义证书上传到系统目录下的,调用这个方法系统会弹出一个对话框让用户选择是否安装指定证书,用户同意后才能将证书放到系统目录,另外并没有api可以删除系统证书,只能用户手动到设置里面删除。