一、使用本地证书库(TrustStore)进行校验
1、下载多个链接对应的证书
2、将两个证书合并为一个TrustStore
输入命令
keytool -import -alias his -file his.cer -keystore truststore
keytool -import -alias avatar -file avatar.cer -keystore truststore
第一次创建需要设置密码
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… 《安全》