Android实现HTTPS单向认证

现在大部分APP内部都做有检查更新功能,如果用HTTP很容易被开发商劫持,所以我们来看一下Android 用HTTPS怎么做。

我刚开始做的时候,由于服务端给我的证书是非认证机构颁发的 (例如12306)或者自签名证书,那么我们是无法直接访问到服务器的,直接访问通常会抛出如下异常:

网上很多解决SSLHandshakeException异常的方案是自定义TrustManager忽略证书校验。

例如:

我用的网络请求框架是okhttp3

1、首先要拿到服务端生成的ce证书和密码

2、配置到自己的项目里,比如raw文件下

3、关键代码

public class SSLSocketFactoryEx extends SSLSocketFactory {

SSLContext sslContext = SSLContext.getInstance("TLS");

public SSLSocketFactoryEx(KeyStore truststore) throws NoSuchAlgorithmException,

KeyManagementException, KeyStoreException,

UnrecoverableKeyException {

super(truststore);

TrustManager tm = new X509TrustManager() {

public java.security.cert.X509Certificate[] getAcceptedIssuers() {

return null;

}

@Override

public void checkClientTrusted(

java.security.cert.X509Certificate[] chain, String authType)

throws java.security.cert.CertificateException {

}

@Override

public void checkServerTrusted(

java.security.cert.X509Certificate[] chain, String authType)

throws java.security.cert.CertificateException {

}

};

sslContext.init(null, new TrustManager[] { tm }, null);

}

@Override

public Socket createSocket(Socket socket, String host, int port,

boolean autoClose) throws IOException, UnknownHostException {

return sslContext.getSocketFactory().createSocket(socket, host, port,

autoClose);

}

@Override

public Socket createSocket() throws IOException {

return sslContext.getSocketFactory().createSocket();

}

}


private OkHttpClient mClient;//OKHttpClient;

InputStream inputStream = App.sContext.getResources().openRawResource(R.raw.tomcat);//证书文件名

        HttpsUtils.SSLParams sslParams = HttpsUtils.getSslSocketFactory(null,inputStream,

                "服务端给的密码,");

        mClient = new OkHttpClient.Builder()

                .sslSocketFactory(sslParams.sSLSocketFactory, sslParams.trustManager)

                .hostnameVerifier(new HostnameVerifier() {

                    @Override

                    public boolean verify(String hostname, SSLSession session) {

                        //直接返回true 即验证成功,即忽略认证

                        return true;

                    }

                })

        .build();

        OkHttpUtils.initClient(mClient);

Okhttp绑定证书实现HTTPS单项认证

对于上述情况中存在的安全隐患,我们应该如何应对?最简单的解决方案就是在客户端内置服务器的证书,我们在校验服务端证书的时候只比对和App内置的证书是否完全相同,如果不同则断开连接。那么此时再遭遇中间人攻击劫持我们的请求时由于黑客服务器没有相应的证书,此时HTTPS请求校验不通过,则无法与黑客的服务器建立起连接。

那么接下来我们就结合Retrofit以访问12306为例来实现HTTPS的单项认证。

首先从12306网站下载签名证书,并放置到我们项目资源目录raw下。然后根据证书构造SSLSocketFactory,代码如下:

/**

* 单项认证

*/

public static SSLSocketFactory getSSLSocketFactoryForOneWay(InputStream... certificates){

try{

CertificateFactory certificateFactory = CertificateFactory.getInstance(CLIENT_TRUST_MANAGER, CLIENT_TRUST_PROVIDER); KeyStore keyStore = KeyStore.getInstance(CLIENT_TRUST_KEYSTORE);

keyStore.load(null);

intindex =0;

for(InputStream certificate : certificates) {

String certificateAlias = Integer.toString(index++);

keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));

try{

if(certificate !=null)

certificate.close();

}catch(IOException e) {

e.printStackTrace();

}

}

SSLContext sslContext = SSLContext.getInstance(CLIENT_AGREEMENT);

TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(keyStore);

sslContext.init(null, trustManagerFactory.getTrustManagers(),newSecureRandom());

return sslContext.getSocketFactory();

}catch(Exception e) {

e.printStackTrace();

}

return null;

}

接下来为OKHttpClient设置SslSocketFactory以及hostnameVerifier,代码如下:

InputStream certificate12306 = Utils.getContext().getResources().openRawResource(R.raw.srca);

OkHttpClient okHttpClient =newOkHttpClient.Builder()

.readTimeout(Constants.DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS)

.connectTimeout(Constants.DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS)

.addInterceptor(interceptor)

.addInterceptor(newHttpHeaderInterceptor())

.addNetworkInterceptor(newHttpCacheInterceptor())

.sslSocketFactory(SslContextFactory.getSSLSocketFactoryForOneWay(certificate12306))

.hostnameVerifier(newSafeHostnameVerifier())

.cache(cache)

.build();

上述代码中hostnameVerifier是对服务器的校验,SafeHostnameVerifier代码如下:

private class SafeHostnameVerifier implements HostnameVerifier{

@Override

public boolean verify(String hostname, SSLSession session){

        if(Constants.IP.equals(hostname)) {

                //校验hostname是否正确,如果正确则建立连接

                return true;

            }

            return false;

}}

verify方法中对比了请求的IP和服务器的IP是否一致,一致则返回true表示校验通过,否则返回false,检验不通过,断开连接。对于网上有些处理是直接返回true,即不对请求的服务器IP做校验,我们不推荐这样使用。而且现在谷歌应用商店已经对此种做法做了限制,禁止在verify方法中直接返回true的App上线。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,546评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,224评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,911评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,737评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,753评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,598评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,338评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,249评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,696评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,888评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,013评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,731评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,348评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,929评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,048评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,203评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,960评论 2 355

推荐阅读更多精彩内容