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

引言

      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 <CN=***, OU=***, O=***, L=***, ST=***, C=CN> 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,修改如下:

1 <Connector port="8444" protocol="org.apache.coyote.http11.Http11NioProtocol" 
2            maxThreads="150" 
3            SSLEnabled="true" scheme="https" secure="true"
4            keystoreFile="${catalina.base}/key/server.keystore" keystorePass="123456"
5            
6            clientAuth="true" sslProtocol="TLS"
7            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
添加

1 <security-constraint>       
2     <web-resource-collection>
3         <web-resource-name >SSL</web-resource-name>  
4         <url-pattern>/*</url-pattern>
5     </web-resource-collection>
6     <user-data-constraint>
7         <transport-guarantee>CONFIDENTIAL</transport-guarantee>  
8     </user-data-constraint>
9 </security-constraint>

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

第二步:Android工具类

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

 1 public class HttpClientSslHelper {
 2     private static final String KEY_STORE_TYPE_BKS = "bks";
 3     private static final String KEY_STORE_TYPE_P12 = "PKCS12";
 4     private static final String SCHEME_HTTPS = "https";
 5     private static final int HTTPS_PORT = 8444;
 6     
 7     private static final String KEY_STORE_CLIENT_PATH = "client.p12";
 8     private static final String KEY_STORE_TRUST_PATH = "client.truststore";
 9     private static final String KEY_STORE_PASSWORD = "123456";
10     private static final String KEY_STORE_TRUST_PASSWORD = "123456";
11     private static KeyStore keyStore;
12     private static KeyStore trustStore;
13     public static HttpClient getSslHttpClient(Context pContext) {
14         HttpClient httpsClient = new DefaultHttpClient();
15         try {
16             // 服务器端需要验证的客户端证书
17             keyStore = KeyStore.getInstance(KEY_STORE_TYPE_P12);
18             
19             // 客户端信任的服务器端证书
20             trustStore = KeyStore.getInstance(KEY_STORE_TYPE_BKS);
21             
22             InputStream ksIn = pContext.getResources().getAssets().open(KEY_STORE_CLIENT_PATH);
23             InputStream tsIn = pContext.getResources().getAssets().open(KEY_STORE_TRUST_PATH);
24             try {
25                 keyStore.load(ksIn, KEY_STORE_PASSWORD.toCharArray());
26                 trustStore.load(tsIn, KEY_STORE_TRUST_PASSWORD.toCharArray());
27             } catch (Exception e) {
28                 e.printStackTrace();
29             } finally {
30                 try {
31                     ksIn.close();
32                 } catch (Exception ignore) {
33                 }
34                 try {
35                     tsIn.close();
36                 } catch (Exception ignore) {
37                 }
38             }
39             SSLSocketFactory socketFactory = new SSLSocketFactory(keyStore, KEY_STORE_PASSWORD, trustStore);
40             Scheme sch = new Scheme(SCHEME_HTTPS, socketFactory, HTTPS_PORT);
41             httpsClient.getConnectionManager().getSchemeRegistry().register(sch);
42         } catch (KeyManagementException e) {
43             e.printStackTrace();
44         } catch (UnrecoverableKeyException e) {
45             e.printStackTrace();
46         } catch (KeyStoreException e) {
47             e.printStackTrace();
48         } catch (FileNotFoundException e) {
49             e.printStackTrace();
50         } catch (NoSuchAlgorithmException e) {
51             e.printStackTrace();
52         } catch (ClientProtocolException e) {
53             e.printStackTrace();
54         } catch (IOException e) {
55             e.printStackTrace();
56         }
57         return httpsClient;
58     }
59 }

实例代码:

 1 AsyncTask testTask = new AsyncTask() {
 2             @Override
 3             protected Object doInBackground(Object... params) {
 4                 try {
 5                     HttpClient httpsClient = AppSslApplication.getHttpsClient(MainActivity.this.getBaseContext());
 6                     HttpGet httpget = new HttpGet(HTTPS_URL);
 7                     HttpResponse response = httpsClient.execute(httpget);
 8                     HttpEntity entity = response.getEntity();
 9                     Log.e("Response status", response.getStatusLine().toString());
10                     if (entity != null) {
11                         Log.e("Response", "Response content length: " + entity.getContentLength());
12                         BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent()));
13                         String text;
14                         while ((text = bufferedReader.readLine()) != null) {
15                             Log.e("Response status", text);
16                         }
17                         bufferedReader.close();
18                     }
19                     httpsClient.getConnectionManager().shutdown();
20                 } catch (ClientProtocolException e) {
21                     e.printStackTrace();
22                 } catch (IllegalStateException e) {
23                     e.printStackTrace();
24                 } catch (IOException e) {
25                     e.printStackTrace();
26                 }
27                 return null;
28             }
29         };
30         testTask.execute();

参考:http://blog.csdn.net/yuxiaohui78/article/details/41975915

转载于:https://www.cnblogs.com/innchina/p/5554949.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值