zoukankan      html  css  js  c++  java
  • 客户端证书认证请求实操

     问题1:什么叫做客户端证书认证?

    答案:通过客户端证书(服务端分发的私人证书或者是通过第三方认证的证书)+账号密码进行身份认证的行为。

    问题2:为什么有客户端证书这么个东西?

    答案:如何加强服务器的用户身份验证系统?一个方法是通过服务端证书认证,就是通过https进行访问。另一个方法是客户端证书认证。通过暴力破解的方式任然可以获取到用户密码,尽管有强密码策略,仅仅只是依靠密码还是不太保险,这个时候就需要客户端证书认证。用户通过服务端颁发的证书+密码,可以极大的加强安全性。

    问题3:怎么使用客户端证书认证?

    答案:如下文

    客户端证书认证

    1.首先准备一个证书(本例以私人证书为例,证书生成方式具体请度娘),记录下证书最后的加密密码。

    2.服务器配置相应的客户端证书认证设置(本例不涉及服务端配置)

    3.配置java类库信任个人证书

      1 package sz.shuwen.utils;
      2 /*
      3  * Copyright 2006 Sun Microsystems, Inc.  All Rights Reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *
      9  *   - Redistributions of source code must retain the above copyright
     10  *     notice, this list of conditions and the following disclaimer.
     11  *
     12  *   - Redistributions in binary form must reproduce the above copyright
     13  *     notice, this list of conditions and the following disclaimer in the
     14  *     documentation and/or other materials provided with the distribution.
     15  *
     16  *   - Neither the name of Sun Microsystems nor the names of its
     17  *     contributors may be used to endorse or promote products derived
     18  *     from this software without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
     21  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 /**
     33  * Originally from:
     34  * http://blogs.sun.com/andreas/resource/InstallCert.java
     35  * Use:
     36  * java InstallCert hostname
     37  * Example:
     38  *% java InstallCert ecc.fedora.redhat.com
     39  */
     40 
     41 import javax.net.ssl.*;
     42 import java.io.*;
     43 import java.security.KeyStore;
     44 import java.security.MessageDigest;
     45 import java.security.cert.CertificateException;
     46 import java.security.cert.X509Certificate;
     47 
     48 /**
     49  * Class used to add the server's certificate to the KeyStore
     50  * with your trusted certificates.
     51  */
     52 public class InstallCert {
     53 
     54     /*public static void main(String[] args) throws Exception {
     55         handle("XXX.com",443,"changeit");
     56     }*/
     57 
     58     public static void handle(String host,int port,String passphraseStr) throws Exception{
     59         char[] passphrase=passphraseStr.toCharArray();
     60         /*if ((args.length == 1) || (args.length == 2)) {
     61             String[] c = args[0].split(":");
     62             host = c[0];
     63             port = (c.length == 1) ? 443 : Integer.parseInt(c[1]);
     64             String p = (args.length == 1) ? "changeit" : args[1];
     65             passphrase = p.toCharArray();
     66         } else {
     67             System.out.println("Usage: java InstallCert <host>[:port] [passphrase]");
     68             return;
     69         }*/
     70 
     71         File file = new File("cacerts");
     72         if (file.isFile() == false) {
     73             char SEP = File.separatorChar;
     74             File dir = new File(System.getProperty("java.home") + SEP
     75                     + "lib" + SEP + "security");
     76             file = new File(dir, "jssecacerts");
     77             if (file.isFile() == false) {
     78                 file = new File(dir, "cacerts");
     79             }
     80         }
     81         System.out.println("Loading KeyStore " + file + "...");
     82         InputStream in = new FileInputStream(file);
     83         KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
     84         ks.load(in, passphrase);
     85         in.close();
     86 
     87         SSLContext context = SSLContext.getInstance("TLS");
     88         TrustManagerFactory tmf =
     89                 TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
     90         tmf.init(ks);
     91         X509TrustManager defaultTrustManager = (X509TrustManager) tmf.getTrustManagers()[0];
     92         SavingTrustManager tm = new SavingTrustManager(defaultTrustManager);
     93         context.init(null, new TrustManager[]{tm}, null);
     94         SSLSocketFactory factory = context.getSocketFactory();
     95 
     96         System.out.println("Opening connection to " + host + ":" + port + "...");
     97         SSLSocket socket = (SSLSocket) factory.createSocket(host, port);
     98         socket.setSoTimeout(10000);
     99         try {
    100             System.out.println("Starting SSL handshake...");
    101             socket.startHandshake();
    102             socket.close();
    103             System.out.println();
    104             System.out.println("No errors, certificate is already trusted");
    105         } catch (SSLException e) {
    106             System.out.println();
    107             e.printStackTrace(System.out);
    108         }
    109 
    110         X509Certificate[] chain = tm.chain;
    111         if (chain == null) {
    112             System.out.println("Could not obtain server certificate chain");
    113             return;
    114         }
    115 
    116         BufferedReader reader =
    117                 new BufferedReader(new InputStreamReader(System.in));
    118 
    119         System.out.println();
    120         System.out.println("Server sent " + chain.length + " certificate(s):");
    121         System.out.println();
    122         MessageDigest sha1 = MessageDigest.getInstance("SHA1");
    123         MessageDigest md5 = MessageDigest.getInstance("MD5");
    124         for (int i = 0; i < chain.length; i++) {
    125             X509Certificate cert = chain[i];
    126             System.out.println
    127                     (" " + (i + 1) + " Subject " + cert.getSubjectDN());
    128             System.out.println("   Issuer  " + cert.getIssuerDN());
    129             sha1.update(cert.getEncoded());
    130             System.out.println("   sha1    " + toHexString(sha1.digest()));
    131             md5.update(cert.getEncoded());
    132             System.out.println("   md5     " + toHexString(md5.digest()));
    133             System.out.println();
    134         }
    135         //注释
    136         /*System.out.println("Enter certificate to add to trusted keystore or 'q' to quit: [1]");
    137         String line = reader.readLine().trim();*/
    138         String line="1";
    139         int k;
    140         try {
    141             k = (line.length() == 0) ? 0 : Integer.parseInt(line) - 1;
    142         } catch (NumberFormatException e) {
    143             System.out.println("KeyStore not changed");
    144             return;
    145         }
    146 
    147         X509Certificate cert = chain[k];
    148         String alias = host + "-" + (k + 1);
    149         ks.setCertificateEntry(alias, cert);
    150 
    151         OutputStream out = new FileOutputStream("jssecacerts");
    152         ks.store(out, passphrase);
    153         out.close();
    154 
    155         System.out.println();
    156         System.out.println(cert);
    157         System.out.println();
    158         System.out.println
    159                 ("Added certificate to keystore 'jssecacerts' using alias '"
    160                         + alias + "'");
    161     }
    162 
    163 
    164     private static final char[] HEXDIGITS = "0123456789abcdef".toCharArray();
    165 
    166     private static String toHexString(byte[] bytes) {
    167         StringBuilder sb = new StringBuilder(bytes.length * 3);
    168         for (int b : bytes) {
    169             b &= 0xff;
    170             sb.append(HEXDIGITS[b >> 4]);
    171             sb.append(HEXDIGITS[b & 15]);
    172             sb.append(' ');
    173         }
    174         return sb.toString();
    175     }
    176 
    177     private static class SavingTrustManager implements X509TrustManager {
    178 
    179         private final X509TrustManager tm;
    180         private X509Certificate[] chain;
    181 
    182         SavingTrustManager(X509TrustManager tm) {
    183             this.tm = tm;
    184         }
    185 
    186         public X509Certificate[] getAcceptedIssuers() {
    187        
    188         /** 
    189          * This change has been done due to the following resolution advised for Java 1.7+
    190         http://infposs.blogspot.kr/2013/06/installcert-and-java-7.html
    191                 **/ 
    192         
    193         return new X509Certificate[0];    
    194             //throw new UnsupportedOperationException();
    195         }
    196 
    197         public void checkClientTrusted(X509Certificate[] chain, String authType)
    198                 throws CertificateException {
    199             throw new UnsupportedOperationException();
    200         }
    201 
    202         public void checkServerTrusted(X509Certificate[] chain, String authType)
    203                 throws CertificateException {
    204             this.chain = chain;
    205             tm.checkServerTrusted(chain, authType);
    206         }
    207     }
    208 }

    该类是在github上找的(感谢大佬),我注释的两处便是修改的地方,可也以取上面的链接看看大佬的代码,我把原方法通过main启动改为通过接口调用传参了。

    4.调用

    本例介绍两种调用方式:

    a.通过postman调用

      关闭公有证书校验,因为本例是个人证书,若是公有证书可以开启。

     

      添加域名证书配置,作用是访问该域名才会携带配置的相应证书

       

      CRT FILE:证书文件(含公钥)

           KEY FILE:私钥文件

            PFX FILE: 后缀为p12的加密证书文件

           Passphrase:加密证书的密码,就是生成加密证书的那个密码

        这四个参数如何填写,依据生成的证书实际情况来即可,下图是我的配置:

    打开postman控制台查看调用结果

    b.通过java代码调用

     1 /**
     2      * 发送 SSL POST 请求(HTTPS),JSON形式
     3      * @param apiUrl API接口URL
     4      * @param json JSON对象
     5      * @return
     6      */
     7     public static String doPostSSL(String apiUrl, Object json) {
     8         CloseableHttpResponse response = null;
     9         String httpStr = "";
    10         try {
    11             response=doPostSSLRequest(apiUrl,json);
    12             if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
    13                 httpStr = EntityUtils.toString(response.getEntity(), "UTF-8");
    14             }
    15         } catch (Exception e) {
    16             e.printStackTrace();
    17         } finally {
    18             if (response != null) {
    19                 try {
    20                     EntityUtils.consume(response.getEntity());
    21                 } catch (IOException e) {
    22                     e.printStackTrace();
    23                 }
    24             }
    25         }
    26         return httpStr;
    27     }
    28 
    29     /**
    30     *@Author: pengshihao
    31     *@Description:带证书
    32     *@Date: 2019/7/4
    33     */
    34     public static CloseableHttpResponse  doPostSSLRequest(String apiUrl, Object json) throws Exception{
    35         //注意PKCS12证书
    36         KeyStore keyStore = KeyStore.getInstance("PKCS12");
    37         //指向你的证书的绝对路径,带着证书去访问
    38         FileInputStream instream = new FileInputStream(new File(Constant.SSL_CERT_PATH));
    39         //证书的密码,创建证书时的密码
    40         keyStore.load(instream, Constant.SSL_CERT_PASSWORD.toCharArray());
    41         SSLContext sslContext = new SSLContextBuilder().loadKeyMaterial(keyStore,Constant.SSL_CERT_PASSWORD.toCharArray()).build();
    42         SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext,
    43                 new String[] { "TLSv1" },null, SSLConnectionSocketFactory.getDefaultHostnameVerifier());
    44 
    45         CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
    46 
    47         HttpPost httpPost = new HttpPost(apiUrl);
    48         httpPost.addHeader("Accept", "*/*");
    49         httpPost.setHeader("Connection","Keep-Alive");
    50         httpPost.setHeader("Content-Type","application/json;charset=utf-8");
    51         httpPost.setHeader("Host",Constant.DATA_BASE_HOST);
    52         httpPost.addHeader("Cache-Control", "max-age=0");
    53         httpPost.setEntity(new StringEntity(json.toString(),"UTF-8"));//解决中文乱码问题
    54 
    55         return httpClient.execute(httpPost);
    56     }

    以上就是具体的实操。

  • 相关阅读:
    结对编程项目作业2-结对编项目设计文档
    20170914-构建之法:现代软件工程-阅读笔记
    课后作业-阅读任务-阅读提问-1
    GIT 的使用方法
    团队-井字棋-需求分析
    结对-贪吃蛇-需求分析
    python_基础_0
    Unix_07_文件系统高级操作_2
    Unix_06_文件系统高级操作_1
    Unix_05_文件系统高级操作_0
  • 原文地址:https://www.cnblogs.com/potatoChicken/p/11147307.html
Copyright © 2011-2022 走看看