文档章节

基于java的https双向认证,android上亦可用

ilovej
 ilovej
发布于 2014/10/31 11:21
字数 1924
阅读 3601
收藏 122

概述:
客户端,浏览器或者使用http协议和服务器通信的程序。
如:
客户端通过浏览器访问某一网站时,如果该网站为HTTPS网站,浏览器会自动检测系统中是否存在该网站的信任证书,
如果没有信任证书,浏览器一般会拒绝访问,IE会有一个继续访问的链接,但地址栏是红色,给予用户警示作用,
即客户端验证服务端并不是强制性的,可以没有服务端的信任证书,当然是否继续访问完全取决于用户自己。
如果要去除地址栏的红色警告,需要导入服务端提供的证书到浏览器中。

服务器端,使用http协议提供服务的程序。
服务端需要获取到客户端通过浏览器发送过来的认证证书,
如:
该证书在服务端的证书库中已存在,仅仅是个匹配过程,匹配成功即通过认证,可继续访问网站资源,反之则无法显示网页。

基本逻辑:
1、生成服务端密钥库并导出证书.
2、生成客户端密钥库并导出证书.
3、根据服务端密钥库生成客户端信任的证书.
4、将客户端证书导入服务端密钥库.
5、将服务端证书导入浏览器.

源码下载地址:http://pan.baidu.com/s/1eQ5r9OA


生成密钥库和证书:
因使用java环境,下面使用jdk下面的keytool工具来生成相应的密钥库和证书
下面的命令是在windows 7 下面测试通过的,可以直接复制使用
1、创建目录,如d:/sslDemo

2、使用资源管理进入d:/sslDemo,按住shift+右键,弹出菜单,选择"在此处打开命令行".

3、服务器端相关操作
3.1、生成服务器证书库
keytool -validity 36500 -genkey -v -alias server -keyalg RSA -keystore server.keystore -dname "CN=www.itjoyee.com,OU=itjoyee.com,O=itjoyee.com,L=Wuhan,ST=HuBei,c=cn" -storepass 123456 -keypass 123456
注: 服务器证书库参数“CN”必须与服务端的IP地址相同,否则会报错,客户端的任意。

3.2、从服务器证书库中导出服务器证书
keytool -export -v -alias server -keystore server.keystore -storepass 123456 -rfc -file server.cer

3.3、生成客户端信任证书库(由服务端证书生成的证书库,客户端使用此证书验证服务端来源可靠)
keytool -import -v -alias server -file server.cer -keystore client.truststore -storepass 123456 -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider

注:-storetype BKS 是生成android上面可以识别的格式,如果不指定jdk默认生成的格式是JKS.
-provider org.bouncycastle.jce.provider.BouncyCastleProvider,需要下载jar包bcprov-jdk16-1.46.jar放到jdk1.7.0_65\jre\lib\ext\目录下.
注意需要jdk16,其他的版本android下面有版本不匹配的问题.


4、客户端相关操作
4.1、生成客户端证书库
keytool -validity 36500 -genkeypair -v -alias client -keyalg RSA -storetype PKCS12 -keystore client.p12 -dname "CN=clients.itjoyee.com,OU=jiajianfa,O=jiajianfa,L=Wuhan,ST=HuBei,c=cn" -storepass 123456 -keypass 123456

4.2、从客户端证书库中导出客户端证书
keytool -export -v -alias client -keystore client.p12 -storetype PKCS12 -storepass 123456 -rfc -file client.cer

注:客户端证书可以产生多个.

4.3、将客户端证书导入到服务器证书库(使得服务器信任客户端证书,服务器端用此验证客户端的合法性)
keytool -import -v -alias client -file client.cer -keystore server.keystore -storepass 123456

4.4、查看服务端证书中信任的客户端证书
keytool -list -keystore server.keystore -storepass 123456

5、服务器端配置
由于使用tomcat,下面使用tomcat做为实例配置.
5.1、在tomcat安装目录下新建key目录,将上面生成的server.keystore复制过去.
5.2、编辑tomcat安装目录下的conf目录下的server.xml,如:d:\sslDemo\apache-tomcat-7.0.55\conf\server.xml
找到Connector,修改如下:

<Connector port="8444" protocol="org.apache.coyote.http11.Http11NioProtocol" 
           maxThreads="150" 
           SSLEnabled="true" scheme="https" secure="true"
           keystoreFile="${catalina.base}/key/server.keystore" keystorePass="123456"
           
           clientAuth="true" sslProtocol="TLS"
           truststoreFile="${catalina.base}/key/server.keystore" truststorePass="123456"/>

注:           
port配置https访问的端口
SSLEnabled="true" 开启https服务
scheme="https"
secure="true"    开启服务端安全通信,客户端获取服务器端证书
keystoreFile="${catalina.base}/key/server.keystore" keystorePass="123456" 服务器证书库

clientAuth="true" 开启验证客户端
sslProtocol="TLS" 使用的协议
truststoreFile="${catalina.base}/key/server.keystore" truststorePass="123456" 服务器证书库(已导入客户端证书)

6、测试
由于生成证书CN配置的是www.itjoyee.com,故需要修改C:\Windows\System32\drivers\etc\hosts
添加

192.168.0.50    www.itjoyee.com
注:
192.168.0.50 为服务器的ip

启动tomcat
打开浏览器
地址栏输入 http://www.itjoyee.com:8080/
可以访问

地址栏输入https://www.itjoyee.com:8444/
访问结果,为无法显示,因为,没有使服务器端生成的信任的客户端证书

双击client.p12,输入密码,在此访问https://www.itjoyee.com:8444/
此时会有证书相关的提示,点击"确认",接着会提示网站安全证书有问题,点击继续访问,即可进入正常访问页面

7、tomcat下的服务强制使用ssl配置
已ROOT服务为例,修改D:\sslDemo\apache-tomcat-7.0.55\webapps\ROOT\WEB-INF\web.xml
添加

<security-constraint>       
    <web-resource-collection>
        <web-resource-name >SSL</web-resource-name>  
        <url-pattern>/*</url-pattern>
    </web-resource-collection>
    <user-data-constraint>
        <transport-guarantee>CONFIDENTIAL</transport-guarantee>  
    </user-data-constraint>
</security-constraint>

打开浏览器
地址栏输入 http://www.itjoyee.com:8080/会有证书相关提示


为了方便测试android下双向认证可以用,生成证书的时候把域名换成服务器的ip地址,验证才可以通过

1、android app 代码实现

AsyncTask testTask = new AsyncTask() {
            @Override
            protected Object doInBackground(Object... params) {
                try {
                    HttpClient httpsClient = AppSslApplication.getHttpsClient(MainActivity.this.getBaseContext());
                    HttpGet httpget = new HttpGet(HTTPS_URL);
                    HttpResponse response = httpsClient.execute(httpget);
                    HttpEntity entity = response.getEntity();
                    Log.e("Response status", response.getStatusLine().toString());
                    if (entity != null) {
                        Log.e("Response", "Response content length: " + entity.getContentLength());
                        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent()));
                        String text;
                        while ((text = bufferedReader.readLine()) != null) {
                            Log.e("Response status", text);
                        }
                        bufferedReader.close();
                    }
                    httpsClient.getConnectionManager().shutdown();
                } catch (ClientProtocolException e) {
                    e.printStackTrace();
                } catch (IllegalStateException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return null;
            }
        };
        testTask.execute();
public class HttpClientSslHelper {
    private static final String KEY_STORE_TYPE_BKS = "bks";
    private static final String KEY_STORE_TYPE_P12 = "PKCS12";
    private static final String SCHEME_HTTPS = "https";
    private static final int HTTPS_PORT = 8444;
    
    private static final String KEY_STORE_CLIENT_PATH = "client.p12";
    private static final String KEY_STORE_TRUST_PATH = "client.truststore";
    private static final String KEY_STORE_PASSWORD = "123456";
    private static final String KEY_STORE_TRUST_PASSWORD = "123456";
    private static KeyStore keyStore;
    private static KeyStore trustStore;
    public static HttpClient getSslHttpClient(Context pContext) {
        HttpClient httpsClient = new DefaultHttpClient();
        try {
            // 服务器端需要验证的客户端证书
            keyStore = KeyStore.getInstance(KEY_STORE_TYPE_P12);
            
            // 客户端信任的服务器端证书
            trustStore = KeyStore.getInstance(KEY_STORE_TYPE_BKS);
            
            InputStream ksIn = pContext.getResources().getAssets().open(KEY_STORE_CLIENT_PATH);
            InputStream tsIn = pContext.getResources().getAssets().open(KEY_STORE_TRUST_PATH);
            try {
                keyStore.load(ksIn, KEY_STORE_PASSWORD.toCharArray());
                trustStore.load(tsIn, KEY_STORE_TRUST_PASSWORD.toCharArray());
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    ksIn.close();
                } catch (Exception ignore) {
                }
                try {
                    tsIn.close();
                } catch (Exception ignore) {
                }
            }
            SSLSocketFactory socketFactory = new SSLSocketFactory(keyStore, KEY_STORE_PASSWORD, trustStore);
            Scheme sch = new Scheme(SCHEME_HTTPS, socketFactory, HTTPS_PORT);
            httpsClient.getConnectionManager().getSchemeRegistry().register(sch);
        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (UnrecoverableKeyException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return httpsClient;
    }
}

2、android浏览器实现
1.先把你的CA证书拷贝到你的SD卡里面
2.进入手机的"设置"->"位置和安全",最下面有个"从SD卡安装",就是安装证书的。
---------暂时没有实现

© 著作权归作者所有

ilovej
粉丝 6
博文 9
码字总数 2370
作品 0
武汉
高级程序员
私信 提问
加载中

评论(2)

都比的不行
楼主 我的怎么一直报证书可靠性无法验证?求解
veney1205
veney1205
楼主好人~4
android httpClient(https/http)的优化构建方式一

参考:基于java的https双向认证,android上亦可用 Android Https相关完全解析 当OkHttp遇到Https 在android中,经常不可避免的的使用https和http访问网络数据,因此需要先构建一个网络访问cli...

IamOkay
2014/10/31
3.1K
0
Android 使用自带的HttpClient进行https请求出现403的解决过程记录

出现的过程 最近在用程序模拟一个web站的https登录,然后进行一些后续操作的小玩意。先使用java程序写测试代码,测试通过移植到android。 java基于httpclient-4.3.1.jar开发。 android端使用...

atearsan
2014/03/05
6.7K
1
搭建局域网WebSocket手机和Web遥控器

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 https://blog.csdn.net/jay100500/article/details/92847893 这里以遥控Android平台的机顶盒...

范特西_jay
06/19
0
0
如何让Java和C++接口互相调用:JNI使用指南

写在前面的话 对于cocos2d-x开发者而言,游戏对多平台的支持是一个刚需,一般而言需要支持Android和iOS。然而,在开发过程中,android 平台遇到的一系列问题着实让人头疼,本文以集成新浪微博...

zhangyujsj
2015/08/23
664
0
开源轻量级 IM 框架 MobileIMSDK v3.0 发布!

一、更新内容简介 本次更新为主版本更新,更新内容包含了简化了消息发送目标的方式、支持Web版与APP版互通、优化了Protocal协议结构等主要升级,详细更新内容见“版本更新说明”部分。 重要提...

JackJiang-
2017/06/30
2.5K
11

没有更多内容

加载失败,请刷新页面

加载更多

Vue warn]: Computed property "activeNames" was assigned to but it has no setter.

在使用 vue,element-ui时,如下代码 <template> <el-form :model="numberValidateForm" ref="numberValidateForm"> <el-form-item> <el-tabs v-model="activeNames" @tab-cl......

牧云橙
23分钟前
3
0
重构-改善既有代码的设计-6.2内联函数

6.2内联函数 动机 本书经常以简短的函数表现动作意图,这样会使代码更清晰易读。但有时候你会遇到某些函数,其内部代码和函数名称同样清晰易读。也可能你充够了该函数的内部实现,使其内容和...

还仙
24分钟前
5
0
Less 混入

混合类似于编程语言中的函数。 Mixins 是一组CSS属性,允许我们将一个类的属性嵌套于另一个类,被嵌入的类可以看作是变量,并且包含类名作为其属性,也就是说我们可以用一个类定义样式然后把...

凌兮洛
26分钟前
5
0
频繁FGC的真凶原来是它

频繁FGC的真凶原来是它 上周排查了一个线上问题,主要现象是CPU占用过高,jvm old区占用过高,同时频繁fgc,我简单排查了下就草草收场了,但是过后我对这个问题又进行了复查,发现问题没有那...

每天晒白牙
27分钟前
5
0
简单的树形菜单如何写

业务需求 数据结构中含有图片、名称、children的树形结构,需要展示出每一级的图片名称和图片,找了些树形图的插件,都没有展示大的图片的,一般都是小图标,就自己试着写一个包含图的简单的...

tianyawhl
29分钟前
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部