Https安全协议在手机App与后台服务通信上的应用

https://www.cnblogs.com/innchina/p/5554949.html

引言

      App要上苹果支付渠道,苹果支付票据容易被人篡改、伪造,造成平台收益与实际交易额对不上;且由于苹果支付平台暂时没有对账功能,造成很难区分真伪;只能提高应用的安全性,防止支付信息泄露或被篡改,因此打算引入https这种安全传输协议。

什么是Https,与Http有哪儿些异同

     HTTPS(全称:Hypertext Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版。即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。 它是一个URI scheme(抽象标识符体系),句法类同http:体系。用于安全的HTTP数据传输。https:URL表明它使用了HTTP,但HTTPS存在不同于HTTP的默认端口及一个加密/身份验证层(在HTTP与TCP之间)。这个系统的最初研发由网景公司进行,提供了身份验证与加密通讯方法,现在它被广泛用于万维网上安全敏感的通讯,例如交易支付方面。

https协议需要到ca申请证书,一般免费证书很少,需要交费。http是超文本传输协议,信息是明文传输,https 则是具有安全性的ssl加密传输协议;

http和https使用的是完全不同的连接方式用的端口也不一样,前者是80,后者是443。

http的连接很简单,是无状态的,HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全。

HTTPS解决的问题:

1 . 信任主机的问题. 采用https 的server 必须从CA 申请一个用于证明服务器用途类型的证书. 该证书只有用于对应的server 的时候,客户度才信任次主机. 所以目前所有的银行系统网站,关键部分应用都是https 的. 客户通过信任该证书,从而信任了该主机. 其实这样做效率很低,但是银行更侧重安全. 

2 . 通讯过程中的数据的泄密和被窜改。

(摘自百度百科)

      HTTP超文本传输协议 (HTTP-Hypertext transfer protocol) 是一种详细规定了浏览器和万维网服务器之间互相通信的规则,通过因特网传送万维网文档的数据传送协议。

Https请求交互过程

      1.peer终端发送一个request,https服务端把支持的加密算法等以证书的形式返回一个身份信息(包含ca颁发机构和加密公钥等)。

      2.获取证书之后,验证证书合法性。

      3.随机产生一个密钥,并以证书当中的公钥加密。

      4.request https服务端,把用公钥加密过的密钥传送给https服务端。

      5.https服务端用自己的密钥解密,获取随机值。

      6.之后双方传送数据都用此密钥加密后通信。

时序图如下:

第一步:服务器端配置

1、生成密钥库和证书:

因使用java环境,下面使用jdk下面的keytool工具来生成相应的密钥库和证书,下面的命令是在windows 7 下面测试通过的,可以直接复制使用

1)创建目录,如d:/sslDemo

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

3)生成服务器证书库

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地址相同,否则会报错,客户端的任意。(有些信息可有可无,例如L,St等)

回车,会提示你输入一些个人信息及组织信息如:

What is your first and last name?

What is the name of your organizational unit?

What is the name of your organization?

What is the name of your City or Locality?

What is the name of your State or Province?

What is the two-letter country code for this unit?

Is correct?

这里输入yes,回车即可。

公共名称(cn)应该是服务器的域名。 

JDK中keytool常用命令 

-genkey      在用户主目录中创建一个默认文件".keystore",还会产生一个mykey的别名,mykey中包含用户的公钥、私钥和证书

-alias       产生别名

-keystore    指定密钥库的名称(产生的各类信息将不在.keystore文件中

-keyalg      指定密钥的算法

-validity    指定创建的证书有效期多少天

-keysize     指定密钥长度

-storepass   指定密钥库的密码

-keypass     指定别名条目的密码

-dname       指定证书拥有者信息 例如:  "CN=sagely,OU=atr,O=szu,L=sz,ST=gd,C=cn"

-list        显示密钥库中的证书信息      keytool -list -v -keystore sage -storepass ....

-v           显示密钥库中的证书详细信息

-export      将别名指定的证书导出到文件  keytool -export -alias caroot -file caroot.crt

-file        参数指定导出到文件的文件名

-delete      删除密钥库中某条目          keytool -delete -alias sage -keystore sage

-keypasswd   修改密钥库中指定条目口令    keytool -keypasswd -alias sage -keypass .... -new .... -storepass ... -keystore sage

-import      将已签名数字证书导入密钥库  keytool -import -alias sage -keystore sagely -file sagely.crt

导入已签名数字证书用keytool -list -v 以后可以明显发现多了认证链长度,并且把整个CA链全部打印出来。

4)从服务器证书库中导出服务器证书(如果是web服务到此可以结束)

keytool -export -v -alias server -keystore server.keystore -storepass 123456 -rfc -file server.cer

5)生成客户端信任证书库(由服务端证书生成的证书库,客户端使用此证书验证服务端来源可靠)

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下面有版本不匹配的问题.

6)生成客户端证书库

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

7)从客户端证书库中导出客户端证书

keytool -export -v -alias client -keystore client.p12 -storetype PKCS12 -storepass 123456 -rfc -file client.cer

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

8)将客户端证书导入到服务器证书库(使得服务器信任客户端证书,服务器端用此验证客户端的合法性)

keytool -import -v -alias client -file client.cer -keystore server.keystore -storepass 123456

9)查看服务端证书中信任的客户端证书

keytool -list -keystore server.keystore -storepass 123456

2、服务器端配置

由于使用tomcat,下面使用tomcat做为实例配置.

2.1、在tomcat安装目录下新建key目录,将上面生成的server.keystore复制过去.

2.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" 服务器证书库(已导入客户端证书)

3、测试

由于生成证书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/

此时会有证书相关的提示,点击"确认",接着会提示网站安全证书有问题,点击继续访问,即可进入正常访问页面

4、tomcat下的服务强制使用ssl配置

已ROOT服务为例,修改D:\sslDemo\apache-tomcat-7.0.55\webapps\ROOT\WEB-INF\web.xml

添加

打开浏览器

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

第二步:Android工具类

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

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;

    }

}


实例代码:

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

推荐阅读更多精彩内容