Android 应用程序的 SSL 验证
使用 Web 服务时执行 SSL 验证。
引言
当我们尝试访问托管在 HTTPS 上并通过 SSL 保护的 Web 服务时,需要在我们的应用程序中处理主机验证和/或对等验证。
背景
Android 支持 java.net
和 org.apache
包来访问 Web 服务。 我使用 Apache 包,因为我发现它们比使用 Java 包更有用、更容易。
系统要求
开始
此处显示主机和对等验证。 每个 Android 应用程序都有自己的受信任存储区,称为 KeyStore
。 在 KeyStore
中,我们可以存储用于验证 Web 服务的自签名 SSL 证书。 Android 信任一些受信任的证书,但如果我们的签名证书不在这些证书中签名,那么我们需要将我们的证书添加到应用程序的受信任存储区中。
假设您已经拥有自签名证书(如果没有,请使用 Java 的密钥工具创建一个),让我们使用 Bouncy Castle 将证书添加到密钥库中,以便我们在应用程序中访问它。 就像在 Java 中使用 keytool 创建证书一样,Bouncy Castle 是将证书添加到 Android 密钥库的唯一方法。
1. 创建 KeyStore
下载 Bouncy Castle 并将其解压缩到合适的位置,然后将 .jar 文件添加到类路径中。 打开 cmd,转到应用程序文件夹,然后键入以下命令
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 => 访问密钥库的密码
成功执行命令后,将成功生成 mystore.bks 文件。
2. 创建一个类以使用我们的存储区进行 HTTPS 连接
要使用我们上面创建的存储区,我们必须创建一个自定义的 Apache DefaultHttpClient
,它知道使用该存储区进行 HTTPS 请求。
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
,并设置添加它到存储区时使用的密码。
3. 复制 mystore 文件
将生成的 mystore.bks 文件导入到 res/raw 文件夹中。 这样我们上面的类就可以从那里访问它了。
有了这个,SSL 对等验证就得到了处理。 我们只需要创建一个 MyHttpClient
的实例来代替 DefaultHttpClient
,并且对等验证将由它自己处理。
4. 主机验证的流程
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 {
// If the host is any the hosts to be allowed, return, else throw exception
for (int i=0; i < allowHost.length; i++) {
if (host == allowHost[i])
return;
}
throw SSLException;
}
}
取消注释 MyHttpClient
类中的 setHostVerifier
,我们的类已准备好处理 SSL 主机验证。
就这样。 谢谢。
历史
- 2011.04.25: 初始提交