生產環境**嚴禁**忽略憑證驗證(中間人攻擊風險)。但在開發、測試、內網自簽憑證環境,常需暫時關閉驗證。本文展示 Apache HttpClient 3.x/4.x 兩代實作:構建「信任所有」X509TrustManager → 注入 SSLContext → 建立 SSLSocketFactory → 註冊 Scheme("https")。
CloseableHttpClient createInsecureClient() throws KeyManagementException, NoSuchAlgorithmException {
// 1. 信任所有憑證的 TrustManager
TrustManager trustAll = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) {}
public void checkServerTrusted(X509Certificate[] chain, String authType) {}
public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
};
// 2. SSLContext 初始化
SSLContext sslContext = SSLContext.getInstance("TLS"); // 推薦 TLS
sslContext.init(null, new TrustManager[]{trustAll}, new SecureRandom());
// 3. 允許所有主機名(生產請用 DefaultHostnameVerifier)
HostnameVerifier allowAll = (hostname, session) -> true;
// 4. 建立 HttpClient
return HttpClients.custom()
.setSSLContext(sslContext)
.setSSLHostnameVerifier(allowAll)
.build();
}
// 使用
try (CloseableHttpClient client = createInsecureClient()) {
HttpPost post = new HttpPost("https://api.example.com/endpoint");
post.setEntity(new StringEntity(jsonBody, ContentType.APPLICATION_JSON));
try (CloseableHttpResponse resp = client.execute(post)) {
String result = EntityUtils.toString(resp.getEntity());
// 處理結果
}
}
// 同樣構建 trustAll TrustManager 與 SSLContext
SSLSocketFactory sf = new SSLSocketFactory(sslContext);
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
DefaultHttpClient client = new DefaultHttpClient();
client.getConnectionManager().getSchemeRegistry()
.register(new Scheme("https", sf, 443));
// 後續 client.executeMethod(postMethod)...
若伺服器要求客戶端憑證:
KeyStore clientStore = KeyStore.getInstance("PKCS12");
clientStore.load(new FileInputStream("client.p12"), "password".toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(clientStore, "password".toCharArray());
sslContext.init(kmf.getKeyManagers(), new TrustManager[]{trustAll}, new SecureRandom());
| 風險 | 說明 | 對策 |
|---|---|---|
| 中間人攻擊 (MITM) | 攻擊者攔截流量、偽造憑證、竊取/篡改數據 | **僅限開發/測試/受控內網**;生產**必須**驗證憑證鏈與主機名 |
| 憑證釘選繞過 | App 釘選公鑰哈希防偽造,信任所有會失效 | 測試環境暫時關閉釘選邏輯 |
| 合規違規 | GDPR、PCI-DSS 等要求傳輸加密完整性 | 上線前代碼審查禁止 trustAll 進入主分支 |
// 將自簽 CA 或伺服器憑證匯入 JDK cacerts 或自定義 TrustStore
KeyStore trustStore = KeyStore.getInstance("JKS");
trustStore.load(new FileInputStream("my-truststore.jks"), "changeit".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
// 此方式保留完整驗證鏈,僅擴充信任錨點