https本地证书实现(安卓-java)

https实现方式分为两种

  • 单项认证
  • 双向认证

1.安卓端实现:

1.1 单项认证

  1. Android端通过和服务端发送请求试需要进行认证,认证分为单向认证和双向认证,根据安全性来说还是以双向认证为主。
  2. 实现单向认证时需要服务端提供一个证书,该证书在服务端生成之后是.cer格式的,我们需要用cmd命令行进行转换成.bks格式的。
  3. 该证书的作用是在前段向服务端发送请求是以此来限定要被访问的服务端是否安全,是否可信任访问请求数据,只是在前段做认证,通过之后就可访问服务端,而服务端并没有做任何的认证,这也是单向认证的不足之处,安全系数比较低。
  4. 单向认证的实现代码:生成好的证书需要放到资源文件中。
public static String get(String url) {
      try {

         DefaultHttpClient httpClient = new MyHttpClient();
         HttpGet httpGet = new HttpGet(url);
//       HttpClient httpClient = getHttpClient();
         HttpResponse httpResponse = httpClient.execute(httpGet);
         if(httpResponse.getStatusLine().getStatusCode() == 200){
            HttpEntity httpEntity = httpResponse.getEntity();
            return EntityUtils.toString(httpEntity);
         }
      } catch (Exception e) {
         LogUtil.e(TAG, e.getMessage());
      }
      return null;
   }
把之前的getHttpClient()注释掉重新创建MyHttpClient(),MyHttpClient()中的代码如下:
public class MyHttpClient extends DefaultHttpClient {
    private static Context context;
//此处的PASSWORD为前后端之间的一个密码,唯一标识
    private static final String PASSWORD = "123456";
    public static void setContext(Context context) {
        MyHttpClient.context = context;
    }
    public MyHttpClient() {
    }
    public MyHttpClient(HttpParams params) {
        super(params);
    }

    public MyHttpClient(ClientConnectionManager httpConnectionManager, HttpParams params) {
        super(httpConnectionManager, params);
    }

    @Override
    protected ClientConnectionManager createClientConnectionManager() {
        SchemeRegistry registry = new SchemeRegistry();
        registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));

        // 用我们自己定义的 SSLSocketFactory 在 ConnectionManager 中注册一个 443 端口
        registry.register(new Scheme("https", newSslSocketFactory(), 443));
        return new SingleClientConnManager(getParams(), registry);
    }

    private SSLSocketFactory newSslSocketFactory() {
        try {

            // 取得BKS密钥库实例
            KeyStore trusted = KeyStore.getInstance("BKS");

            // 从资源文件中读取你自己创建的那个包含证书的 keystore 文件
	   // 这个参数改成你的 keystore 文件名
            InputStream in = GzApplication.getAppContext().getResources().openRawResource(R.raw.test); 
            try {

                // 用 keystore 的密码跟证书初始化 trusted
                trusted.load(in, PASSWORD.toCharArray());
            } finally {
                in.close();
            }
            SSLSocketFactory sf = new SSLSocketFactory(trusted);

         //允许所有主机的验证
	// 这个参数可以根据需要调整, 如果对主机名的验证不需要那么严谨, 可以将这个严谨程度调低些.
         sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER); 
            return sf;
        } catch (Exception e) {
            throw new AssertionError(e);
        }
    }
}

1.2 双向认证

双向认证的原理其实和单向大同小异,但是不同是,双向认证需要两个认证证书,也是有服务端提供,格式分别为client.p12client.truststore,这两个证书也是放到android资源文件下面,以提供在代码中读取。

public static String get(String url) {
      try {
         HttpGet httpGet = new HttpGet(url);
//       HttpClient httpClient = getHttpClient();
         HttpResponse httpResponse = httpClient.execute(httpGet);
         if(httpResponse.getStatusLine().getStatusCode() == 200){
            HttpEntity httpEntity = httpResponse.getEntity();
            return EntityUtils.toString(httpEntity);
         }
      } catch (Exception e) {
         LogUtil.e(TAG, e.getMessage());
      }
      return null;
   }

修改getHttpClient()方法中的代码如下:

//https
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 = 443;

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 getHttpClient() {

      HttpClient httpsClient = new DefaultHttpClient();
      try {

         // 服务器端需要验证的客户端证书
         keyStore = KeyStore.getInstance(KEY_STORE_TYPE_P12);
         // 客户端信任的服务器端证书
         trustStore = KeyStore.getInstance(KEY_STORE_TYPE_BKS);

        // 从资源文件中读取你自己创建的那个包含证书的 keystore 文件
	// 这个参数改成你的 keystore 文件名
         InputStream ksIn = GzApplication.getAppContext().getResources().getAssets().open(KEY_STORE_CLIENT_PATH);
         InputStream tsIn = GzApplication.getAppContext().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.服务端实现

2.1 单项认证

2.1.1 生成根证书

keytool -genkeypair -alias ROOTCERT -keyalg RSA -keystore rootlib.jks

 命令解释:生成一对RSA非对称密钥和一个自签名证书,以别名ROOTCERTrootlib中。

 注意:enter后,会提示输入密钥库的使用口令,和填写相关OUCN等信息。如下图:

 

   之后会在你的当前工作目录下生成一个rootlib.jks的文件。

2.1.2 生成证书请求

keytool -genkeypair -alias SERVERCERT -keyalg RSA keystore serverlib.jks
( step1 步骤一样 )

注意:此时您的名字与姓氏是什么” ,需要输入localhost(就是证书请求者的域名)

扫描二维码关注公众号,回复: 2039138 查看本文章
keytool -certreq -file server.csr -alias SERVERCERT -keystore serverlib.jks

命令解释:在serverlib文件中从别名为SERVERCERT中取出公钥和用户信息生 成证书请求,并写入到server.csr文件中。

之后会在你的当前工作目录下生成一个server.csr的文件。

2.1.3 用根证书对证书请求签名,生成应用证书

 keytool -gencert -infile server.csr -outfile servercert.cer -alias ROOTCERT -keystore rootlib.jks

命令解释:使用别名为ROOTCERT的私钥对server.csr证书请求进行签发证书,并导入到servercert.cer 文件中。

2.1.4 导出根证书,添加为客户端受信任的根证书颁发机构中

keytool -exportcert -alias ROOTCERT -file root.cer -keystore rootlib.jks

命令解释:从rootlib.jks将别名ROOTCERT的证书导出到root.cer文件中

回到图形界面,切到命令窗口的工作目录下,会有5个文件。


双击root.cer


点击安装证书,然后下一步,注意:


在证书存储时,选择放入指定的证书存储,点击浏览,选择受信任的根证书颁发 机构,然后确认,下一步,完成,确认添加,即可。

2.1.5 配置tomcat

我们先要更新serverlib.jks中的证书(用根证书签发好的应用证书--servercert.cer)

 keytool -importcert -alias SERVERCERT -file server.cer -keystore serverlib.jks

 此时会报:无法从回复中建立链(这是因为更新的证书无法信任)。我们先要将根证书导入到serverlib.jks中,使之信任

keytool -importcert -alias TRUSTCERT -file root.cer -keystore serverlib.jks

这是在执行1)中的命令,即可更新。

注意:更新证书时的别名不能写错,否则keytool工具会认为添加。

现在开始配置tomcat,修改server.xml文件

<Connector port="443" protocol="org.apache.coyote.http11.Http11Protocol"
         minSpareThreads="5" maxSpareThreads="75"
         enableLookups="true" disableUploadTimeout="true"
         acceptCount="100"  maxThreads="200" SSLEnabled="true" 
            scheme="https" secure="true"
        keystoreFile="E:/key/serverlib.jks" keystorePass="123456"
        clientAuth="false" sslProtocol="TLS"/>

clientAuth:设置是否双向验证,默认为false,设置为true代表双向验证,这里我们一般只做服务器验证

    keystoreFile:服务器证书文件路径

    keystorePass:服务器证书密码

    truststorePass:根证书密码

   注意:tomcathttps端口是8443,我改成了443(https的默认端口),需要将httpredirectPort值也要改成443,这样浏览器发送https请求时才可以重定向到修改的443端口上。


部署一个web应用,修改首页index.jsp

将应用添加到tomcat中,启动tomcat

    在地址栏输入:

    点击Login


   此时再看地址栏,我们点击https前面的锁,就可以看到我们的应用证书了。



在点击证书信息,就可以看我们申请的证书内容了,此时我们再用代理的方式抓包如下:


浏览器与服务器之间数据就会被加密后在传输了。

   注意:在step2时,我们生成证书请求时的 ”您的名字与姓氏是什么的值需要我们的服务的主机名,如果不一致的浏览器访问时就会报错,如下图


这样,一个简单https协议服务我们就搭建好了。

2.2 双向认证

2.2.1 生成密钥库和证书

因使用java环境,下面使用jdk下面的keytool工具来生成相应的密钥库和证书

下面的命令是在windows 7 下面测试通过的,可以直接复制使用

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

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

2.2.2 服务器端相关操作

2.2.2.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地址相同,否则会报错,客户端的任意。

2.2.2.2 从服务器证书库中导出服务器证书

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

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

2.2.3 客户端相关操作

2.2.3.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

2.2.3.2 从客户端证书库中导出客户端证书

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

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

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

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

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

keytool -list -keystore server.keystore -storepass 123456

2.2.4 服务器端配置

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

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

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























猜你喜欢

转载自blog.csdn.net/qq_31463999/article/details/79231764