zoukankan      html  css  js  c++  java
  • 基于java的https双向认证,android上亦可用

    From: http://my.oschina.net/jjface/blog/339144

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

    概述:
    客户端,浏览器或者使用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_65jrelibext目录下.
    注意需要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:sslDemoapache-tomcat-7.0.55confserver.xml
    找到Connector,修改如下:

    1
    2
    3
    4
    5
    6
    7
    <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:WindowsSystem32driversetchosts
    添加

    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:sslDemoapache-tomcat-7.0.55webappsROOTWEB-INFweb.xml
    添加

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <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 代码实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    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卡安装",就是安装证书的。
    ---------暂时没有实现

  • 相关阅读:
    PHP中有多态么
    【Android】九宫格实现
    采用xshell链路本地虚拟机Linux
    读取资源文件的工具.
    dede织梦背景经常使用标签
    PHP第三个教训 PHP基本数据类型
    Linux经常使用的命令(必看)
    易Android登录Demo
    [2013山东ACM]省赛 The number of steps (可能DP,数学期望)
    web开发性能优化---UI接口章
  • 原文地址:https://www.cnblogs.com/oc-bowen/p/5623012.html
Copyright © 2011-2022 走看看