65.9K
CodeProject 正在变化。 阅读更多。
Home

Android 应用程序的 SSL 验证

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.25/5 (6投票s)

2011 年 4 月 25 日

CPOL

3分钟阅读

viewsIcon

96854

downloadIcon

5

使用 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: 初始提交
© . All rights reserved.