在Android应用开发中,与Web服务的交互是常见的需求。为了确保数据传输的安全性,通常会使用SSL证书进行加密。本文将介绍如何在Android应用中处理SSL证书验证,包括创建KeyStore、自定义HttpClient以及处理主机验证。
Android支持使用java.net和org.apache包来访问Web服务。选择使用Apache包,因为相较于Java包,它们更加实用且易于使用。
为了在Android应用中添加SSL证书,需要使用Bouncy Castle库。这是一个开源的加密库,可以让向Android的KeyStore中添加自定义的SSL证书。
每个Android应用都有自己的信任存储库,称为KeyStore。可以在KeyStore中存储自签名的SSL证书,用于Web服务的验证目的。Android信任一些预设的证书,但如果证书不在其中,就需要将其添加到应用的信任存储库中。
首先,需要创建一个KeyStore来存储自签名证书。以下是创建KeyStore的步骤:
keytool -import -v -trustcacerts -alias 0 -file mycertificate.crt \
-keystore res/raw/mystore.bks -storetype BKS -provider \
org.bouncycastle.jce.provider.BouncyCastleProvider -storepass mypassword
其中,file参数指向想要添加的证书文件,keystore参数给想要命名的存储库命名,storepass是访问keystore的密码。
执行命令后,将成功生成mystore.bks文件。
为了使用创建的存储库,需要创建一个自定义的Apache DefaultHttpClient,它知道如何使用存储库进行HTTPS请求。以下是创建自定义HttpClient的代码示例:
public class MyHttpClient extends DefaultHttpClient {
final Context context;
public MyHttpClient(Context context) {
this.context = context;
}
@Override
protected ClientConnectionManager createClientConnectionManager() {
SchemeRegistry registry = new SchemeRegistry();
registry.register("http", PlainSocketFactory.getSocketFactory(), 80);
registry.register("https", newSslSocketFactory(), 443);
return new SingleClientConnManager(getParams(), registry);
}
private SSLSocketFactory newSslSocketFactory() {
try {
KeyStore trusted = KeyStore.getInstance("BKS");
InputStream in = context.getResources().openRawResource(R.raw.mystore);
try {
trusted.load(in, "mypassword".toCharArray());
} finally {
in.close();
}
SSLSocketFactory mySslFact = new SslFactory(trusted);
mySslFact.setHostNameVerifier(new MyHstNameVerifier());
return mySslFact;
} catch (Exception e) {
throw new AssertionError(e);
}
}
}
这段代码帮助接受服务器证书,并设置用于验证的证书。可以看到,如何使用-storename参数"BKS"来获取KeyStore实例,从R.raw加载证书文件mystore,并设置在添加到存储库时使用的密码。
将生成的mystore.bks文件导入到res/raw文件夹中,以便上述类可以从那里访问它。
Android只支持通过哪个主机/域名调用Web服务——如果尝试连接到任何其他主机,它会抛出异常。例如,如果应用连接到一个主机,然后出于任何原因尝试连接到另一个主机,Android将不允许这样做。为了允许这样做,需要设置想要允许应用访问的主机名。
public class MyHostVerifier extends org.apache.http.conn.ssl.AbstractVerifier {
String[] allowHost = {"my.ultra.com", "your.ultra.com", "ours.ultra.com"};
@Override
public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {
// 如果主机是允许的主机之一,则返回,否则抛出异常
for (int i = 0; i < allowHost.length; i++) {
if (host.equals(allowHost[i])) return;
}
throw new SSLException();
}
}
取消注释MyHttpClient类中的setHostVerifier,类就准备好处理SSL主机验证了。