08-HTTPS在HTTPClient的应用

294 阅读2分钟

01-从HTTP到HTTPS

02-HTTPS证书生成、验签 、证书链

03-OpenSSL-创建带SAN扩展的证书并进行CA自签

04-HTTPS证书格式及转换

05-HTTPS 秘钥库与证书(Java)

06-HTTPS单向认证及Java案例

07-HTTPS双向认证及Java案例

08-HTTPS在HTTPClient的应用

10-HTTPS在Nginx中的配置

11-HTTPS在SpringBoot中的配置

12-HTTPS在Tomcat配置

13-SSL-Mysql配置与应用

14-HTTPS在Redis中的配置

15-HTTPS基于Feign的远程调用

16-HTTPS在Eureka中的配置

一、使用本地证书库(TrustStore)进行校验

1、下载多个链接对应的证书

如链接xx.huawei.com/和https://xx…

2、将两个证书合并为一个TrustStore

输入命令

keytool -import -alias his -file his.cer -keystore truststore

keytool -import -alias avatar -file avatar.cer -keystore truststore

第一次创建需要设置密码 image.png

3、加载本地证书TrustStore并返回X509TrustManager

/**
* 根据本地TrustStore返回X509TrustManager
*
* @return X509TrustManager
*/
private static X509TrustManager getKeyStoreX509TrustManager() {
    try (FileInputStream inputStream = new FileInputStream(
        new File("C:\\Users\\xxxx\\Desktop\\cert\\truststore"))) {
        KeyStore trustKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        trustKeyStore.load(inputStream, "Turbo@crt".toCharArray());
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
            TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(trustKeyStore);
        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
        return (X509TrustManager) trustManagers[0];
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return null;
}

4、加载TrustStore X509TrustManager并返回SSLSocketFactory

	/**
	 * 根据本地TrustStore返回SSLSocketFactory
	 *
	 * @return SSLSocketFactory
	 * @throws NoSuchAlgorithmException 异常
	 * @throws KeyManagementException 异常
	 */
	public static SSLSocketFactory createTrustStoreSSLSocketFactory()
	    throws NoSuchAlgorithmException, KeyManagementException {
	    TrustManager[] trustManagers = new TrustManager[] {getKeyStoreX509TrustManager()};
	    SSLContext context = SSLContext.getInstance("TLSv1.2");
	    context.init(null, trustManagers, new SecureRandom());
	    return context.getSocketFactory();
	}

5、具体调用实现

	/**
	 * 测试https 连接,本地证书进行校验,不会报错 使用trustStore 两个网址都可以通过认证
	 */
	private void testHttpClientWithTrustStoreCerCheck() {
	    try {
	        CloseableHttpClient client = HttpClients.custom()
	            .setSSLSocketFactory(new SSLConnectionSocketFactory(SSLUtils.createTrustStoreSSLSocketFactory(),
	                NoopHostnameVerifier.INSTANCE))
	            .build();
	        // HttpGet request = new HttpGet("https://xxx.huawei.com/");
	        HttpGet request = new HttpGet("https://xxx.huawei.com/");
	        HttpResponse response = client.execute(request);
	 
	        int responseCode = response.getStatusLine().getStatusCode();
	        System.out.println(responseCode);
	    } catch (Exception ex) {
	        ex.printStackTrace();
	    }
	}

二、使用对应的本地证书进行校验

1、下载证书

2、加载本地证书并返回SSLSocketFactory

编写 TrustCerManager

	package cert;
	 
	import sun.misc.BASE64Decoder;
	import sun.misc.BASE64Encoder;
	 
	import java.io.IOException;
	import java.security.PublicKey;
	import java.security.cert.Certificate;
	import java.security.cert.CertificateException;
	import java.security.cert.X509Certificate;
	 
	import javax.net.ssl.X509TrustManager;
	 
	/**
	 * 信任本地cer的Manager
	 */
	public class TrustCerManager implements X509TrustManager {
	    private Certificate[] certificates;
	 
	    private String[] localPublicKeyStrs;
	 
	    public TrustCerManager(Certificate[] certificates) {
	        this.certificates = certificates;
	        localPublicKeyStrs = new String[certificates.length];
	        for (int i = 0; i < certificates.length; i++) {
	            Certificate certificate = certificates[i];
	            PublicKey publicKey = certificate.getPublicKey();
	            localPublicKeyStrs[i] = byte2Base64(publicKey.getEncoded());
	        }
	    }
	 
	    @Override
	    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
	 
	    }
	 
	    @Override
	    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
	        if (null != localPublicKeyStrs) {
	            int passCount = 0;
	            for (String publicKeyStr : localPublicKeyStrs) {
	                if (chain != null) {
	                    // 遍历服务端证书信息
	                    for (X509Certificate certificate : chain) {
	                        PublicKey netPublicKey = certificate.getPublicKey();
	                        String netPublicKeyStr = byte2Base64(netPublicKey.getEncoded());
	                        if (publicKeyStr.equals(netPublicKeyStr)) {
	                            passCount++;
	                        }
	                        System.out.println("net PublicKey=" + netPublicKey);
	                    }
	                }
	            }
	            System.out.println("passCount=" + passCount);
	            if (passCount == 0) {
	                // 没有一个能匹配的,抛出异常
	                throw new CertificateException();
	            }
	        } else {
	            System.out.println("no LocalKeyStore");
	            throw new CertificateException();
	        }
	    }
	 
	    @Override
	    public X509Certificate[] getAcceptedIssuers() {
	        return new X509Certificate[0];
	    }
	 
	    /**
	     * bytes 转Base64字符串
	     *
	     * @param bytes 字节数组
	     * @return 字符串
	     */
	    private String byte2Base64(byte[] bytes) {
	        BASE64Encoder encoder = new BASE64Encoder();
	        return encoder.encode(bytes);
	    }
	 
	    /**
	     * base64字符串转bytes
	     *
	     * @param base64Str base64字符串
	     * @return byte数组
	     * @throws IOException 异常
	     */
	    private byte[] base642Byte(String base64Str) throws IOException {
	        BASE64Decoder decoder = new BASE64Decoder();
	        return decoder.decodeBuffer(base64Str);
	    }
	}
	 
	 
	 
	/**
	 * 加载本地证书,并返回SSLSocketFactory
	 *
	 * @return SSLSocketFactory
	 * @throws NoSuchAlgorithmException 异常
	 * @throws KeyManagementException 异常
	 * @throws CertificateException 异常
	 * @throws FileNotFoundException 异常
	 */
	public static SSLSocketFactory createCerSSLSocketFactory()
	    throws NoSuchAlgorithmException, KeyManagementException, CertificateException, FileNotFoundException {
	    CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
	    Certificate certificate = certificateFactory.generateCertificate(
	        new FileInputStream("C:\\Users\\xxx\\Desktop\\cert\\his.cer"));
	 
	    TrustManager[] trustManagers = new TrustManager[] {
	        new TrustCerManager(new Certificate[] {
	            certificate
	        })
	    };
	 
	    SSLContext context = SSLContext.getInstance("TLSv1.2");
	    context.init(null, trustManagers, new SecureRandom());
	    return context.getSocketFactory();
	}

3、具体调用实现

	/**
	 * 测试https 连接,本地证书进行校验,不会报错
	 */
	private void testHttpClientWithLocalCerCheck() {
	    try {
	        CloseableHttpClient client = HttpClients.custom()
	            .setSSLSocketFactory(
	                new SSLConnectionSocketFactory(SSLUtils.createCerSSLSocketFactory(), NoopHostnameVerifier.INSTANCE))
	            .build();
	        HttpGet request = new HttpGet("https://his.huawei.com/");
	        HttpResponse response = client.execute(request);
	 
	        int responseCode = response.getStatusLine().getStatusCode();
	        System.out.println(responseCode);
	    } catch (Exception ex) {
	        ex.printStackTrace();
	    }
	}

4、Spring应用

/**
 * httpsClient
 *
 * @since 2021-09-17
 */
@Component
public class HttpsClientConfig {
    private static final Logger LOGGER = LoggerFactory.getLogger(HttpsClientConfig.class);

    @Value("${server.ssl.key-store}")
    String keyStoreFileName;

    @Value("${server.ssl.key-store-password}")
    String keyStorePassword;

    @Value("${server.ssl.trust-store}")
    String trustStoreFileName;

    @Value("${server.ssl.trust-store-password}")
    String trustStorePassword;

    @Autowired
    private AesCiperServiceUtil aesCiperServiceUtil;

    /**
     * http启用SSL模式
     *
     * @return CloseableHttpClient
     * @throws UnrecoverableKeyException UnrecoverableKeyException
     * @throws CertificateOperationException CertificateOperationException
     */
    @Bean
    public CloseableHttpClient httpsClient() throws UnrecoverableKeyException, CertificateOperationException {
        CodeCCUtils.info(LOGGER, "init httpsClient...");
        String keyStorePwd = aesCiperServiceUtil.decryptStr(keyStorePassword);
        String trustStorePwd = aesCiperServiceUtil.decryptStr(trustStorePassword);
        try {
            SSLContext sslContext = SSLUtil.getSSLContext(keyStoreFileName, keyStorePwd, trustStoreFileName,
                    trustStorePwd);
            SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext,
                    HostnameVerifierUtil.getHostnameVerifier());
            HttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create()
                    .setSSLSocketFactory(sslConnectionSocketFactory)
                    .setConnectionTimeToLive(TimeValue.of(10000, TimeUnit.MILLISECONDS)).build();
            return HttpClients.custom().setConnectionManager(connectionManager).build();
        } finally {
            keyStorePwd = null;
            trustStorePwd = null;
        }
    }
}

更多内容关注微信公众号 ”前后端技术精选“,或者语雀,里面有更多知识:www.yuque.com/riverzmm/uu… 《安全》