突然产生了一个疑问 :什么时候需要去配置忽略SSL证书和主机名验证呢?
通常,配置忽略SSL证书和主机名验证是在以下情况下考虑的:
-
开发或测试环境:在开发或测试环境中,你可能正在与自签名证书或尚未由受信任的证书颁发机构(CA)签名的证书进行交互。这些证书在标准的SSL/TLS验证过程中会被视为无效,因此会导致连接失败。为了继续开发和测试,你可能会选择忽略这些验证。
-
内部网络或受信任的网络:如果你的应用程序在内部网络或你完全控制并信任的网络中运行,那么可能不需要通过标准的SSL/TLS验证来确保安全性。在这种情况下,忽略SSL证书和主机名验证可以减少开发和部署的复杂性。
-
紧急修复或绕过:在极少数情况下,如果生产环境中的SSL/TLS配置出现问题,导致正常业务受到严重影响,而快速修复不可行时,可能会考虑临时忽略SSL证书验证以恢复服务。然而,这应被视为最后的手段,并且应立即着手解决根本问题。
-
教育和学习目的:在学习或教授网络编程和安全性时,为了帮助学生或开发者理解SSL/TLS的工作原理和重要性,可能会故意配置忽略SSL证书验证的环境。
-
然而,需要注意的是,忽略SSL证书和主机名验证会极大地降低应用程序的安全性,使其容易受到中间人攻击等安全威胁。因此,在生产环境中通常不建议这样做,除非在绝对必要的情况下,并且已经采取了其他安全措施来减轻潜在的风险。
-
此外,当决定忽略SSL证书验证时,应该确保只在完全受信任的网络和环境中进行,并且已经明确了解可能带来的安全风险。同时,应该尽快找到并解决导致需要忽略验证的根本原因,以便能够恢复正常的SSL/TLS验证过程。
创建一个用于绕过SSL和主机名验证的RestTemplate 对象
public class RestTemplateUtils {
public static RestTemplate restTemplateHttps() {
RestTemplate restTemplate = null;
try {
//创建一个 TrustStrategy 的匿名实现,该实现简单地返回 true,表示接受任何证书,无论其是否由受信任的证书颁发机构签发。这是忽略 SSL 证书验证的关键步骤。
TrustStrategy acceptingTrustStrategy = (chain, authType) -> true;
//使用 SSLContexts.custom() 创建一个自定义的 SSLContext,并通过调用 loadTrustMaterial 方法加载前面定义的信任策略。然后,通过调用 build() 方法完成 SSLContext 的构建。
SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
//使用前面创建的 SSLContext 和一个 NoopHostnameVerifier(一个不执行任何主机名验证的 HostnameVerifier 实现)来创建一个 SSLConnectionSocketFactory 实例。这允许 HttpClient 忽略主机名验证
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
//创建一个 HttpClientBuilder 实例,用于配置和构建 HttpClient
HttpClientBuilder clientBuilder = HttpClients.custom();
//使用前面创建的 SSLConnectionSocketFactory 实例来配置 HttpClientBuilder,并调用 build() 方法来构建 CloseableHttpClient 实例。这个 HttpClient 实例现在配置为忽略 SSL 证书和主机名验证
CloseableHttpClient httpClient = clientBuilder.setSSLSocketFactory(sslsf).build();
//创建一个 HttpComponentsClientHttpRequestFactory 实例,这个工厂类用于将 HttpClient 实例包装成 ClientHttpRequestFactory,后者是 RestTemplate 需要的
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
//将前面创建的 CloseableHttpClient 实例设置到 HttpComponentsClientHttpRequestFactory 中
requestFactory.setHttpClient(httpClient);
使用前面配置的 HttpComponentsClientHttpRequestFactory 实例来创建 RestTemplate 实例。
restTemplate = new RestTemplate(requestFactory);
} catch (Exception e) {
e.printStackTrace();
}
return restTemplate;
}
工具类使用
public class UserServiceImpl implements UserService
@Value("${ADDRESS}")
String ADDRESS;
public void getUserInfo(UserReqTDO userReqTDO){
String url = ADDRESS + "/my/test/user/getUser";
RestTemplate restTemplateHttps = RestTemplateUtil.restTemplateHttps();
MultiValueMap<String, String> forms = new LinkedMultiValueMap<>();
Map<String, Object> result;
//构建入参
forms.put("requestName", Collections.singletonList(userReqTDO.getUserName()));
forms.put("mainData", Collections.singletonList(userReqTDO.getUserPWd()));
forms.put("detailData", Collections.singletonList(userReqTDO.getUserDepart()));
//设置参数 和请求头
HttpEntity<MultiValueMap<String, String>> httpEntity = new HttpEntity<>(forms, setRequestHeader(String.valueOf(UserWordCode)));
log.info("=======调用/getUser接口=====");
log.info("=======调用/getUsert接口url地址=====" + url);
//发送请求
returnMsg = restTemplateHttps.postForObject(url, httpEntity, String.class);
//解析响应参数
result= JSON.parseObject(returnMsg);
if ("SUCCESS".equals(map.get("response_code"))) {
Map<String, Object> data = (Map<String, Object>) map.get("response_data");
UserName= Long.valueOf(String.valueOf(data.get("UserName")));
code = String.valueOf(map.get("code"));
}
}
// 设置请求头方法
private HttpHeaders setRequestHeader(String userWordCode) {
String token = UserService.getToken();
String userid = UserService.getUserInfo(userWordCode);
RSA rsa = new RSA(null, SPK);
String secretUserid = rsa.encryptBase64(userid, CharsetUtil.CHARSET_UTF_8, KeyType.PublicKey);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
headers.add("token", token);
headers.add("appid", APPID);
headers.add("userid", secretUserid);
return headers;
}