Android应用程序的SSL验证

标签: Android
发布时间: 2014/2/10 9:52:27

简介

当我们试图访问托管在HTTPS且受SSL验证保护的web服务时,主机验证和/或对等验证就需要我们在我们的应用程序中进行处理。

背景

Android支持java.net和org.apache开发包来访问Web服务。我使用的是Apache的包,因为我觉得他们更有用,并且它比Java包更容易使用。

系统要求

实现过程

主机和对等验证将在这里展示给大家。每一个Android应用程序都有自己的受信任存储区,它叫做密钥库。在密钥库,我们可以存储我们自己的,将用来验证我们自己web服务的SSL证书。Android的信任一些的信任证书,但万一如果我们的签名证书不在那些信任证书之列呢?!因此,我们就需要把我们的证书添加到该应用程序的受信任存储区。
假设你已经有一个自己的签名证书(如果没有,请使用Java的密钥工具来创建一个),让我们使用可以进入我们应用程序的Bouncy Castle来添加我们的证书。就像Java的密钥工具来创建证书一样,Bouncy Castle是将证书添加到受信任存储区的唯一方法。

1. 创建受信任存储区

下载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
  • 文件参数指向你想添加的的证书文件所在路径

  • keystore =>取一个你想取得名字

  • storepass =>进入keystore的密码

如果命令正确执行,mystore.bks文件就会被成功创建。

2. 创建使用我们存储区的HTTPS连接的类

为了使用我们上边创建的存储区,我们需要创建一个自定义的Apache 默认客户端,来使用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“来获得密钥库的实例,从R.raw加载证书文件MyStore,并设置在我们使用它时,需要的密码。

3. 复制mystore文件

向 res/raw文件夹引入生成的mystore.bks文件。所以我们上边的类可以从那里接入。
有了这个,SSL对顶验证就处理好了。我们只需要创建一个MyHttpClient 实例来代替ofDefaultHttpClient 。之后,对等验证将会自动执行。

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主机验证了。
就是这样。谢谢。


官方微信
官方QQ群
31647020