注意事項:
1. TrustModifier 使用上需確認 HTTPS Protocol 是否為 TLS
2. 本文供參考及學習使用
Catalog
Abstract
過去小編曾撰寫過不同語言的 HTTPS 連線,必須 PASS 掉 HTTPS 中 X509 和 HostName 的狀況並不算少數,這時以 Python 來講只需要增加一個布林值即可,但在 Java 中卻需要實作兩個類別,為了能更簡單的有效的進行程式開發及測試,小編撰寫了一個 TrustModifier,此類別中僅有一個外部可以呼叫的方法,通過此方法可以快速 PASS 掉 X509 及 HostName 驗證
關於 HTTPS 的小知識
在撰寫爬蟲或串接第三方 API 時,不可避免的在某些情況下必須用到 HTTPS 協定,這時如果對方伺服器所提供的是合法的接口,那在實作上只需要直接用 HTTPS 方式去連接即可。但事實並非總是如此,在測試中或使用到內部網路時,會因為伺服器不被信任而造成程式中斷,就小編所知這時我們的選擇,有以下兩種:
- 將對方伺服器中的憑證加入信任名單,並設法欺騙己方的伺服器,認為對方的 HostName 是正確的
- 在連線過程中無條件 Pass 第一種的兩種檢查
P.S 無論哪一種在傳輸時都仍然有加密,只是目前所要連線的伺服器並未通過驗證可能不安全
TrustModifier.java
import javax.net.ssl.*;
import java.net.URLConnection;
import java.security.cert.*;
/**
* Created by Cookie on 16/8/9.
*/
public class TrustModifier {
private static final HostnameVerifier VERIFIER = new AllowHostnameVerifier();
private static final TrustManager[] MANAGER = new TrustManager[]{new AllowManager()};
private static final TrustModifier MODIFIER = new TrustModifier("TLS");
private final SSLSocketFactory factory;
private TrustModifier(String protocol) {
try {
SSLContext ctx = SSLContext.getInstance(protocol);
ctx.init(null, MANAGER, null);
factory = ctx.getSocketFactory();
} catch (Exception e) {
throw new RuntimeException("Create Trust Modifier Failed.", e);
}
}
private HttpsURLConnection modify(HttpsURLConnection conn) {
conn.setSSLSocketFactory(factory);
conn.setHostnameVerifier(VERIFIER);
return conn;
}
/** Call this method and it will modify connection with trust settings. */
public static URLConnection trust(URLConnection conn) {
return (conn instanceof HttpsURLConnection)?
MODIFIER.modify((HttpsURLConnection) conn) : conn;
}
private static final class AllowHostnameVerifier implements HostnameVerifier {
public boolean verify(String hostname, SSLSession session) {
return true;
}
}
private static final class AllowManager implements X509TrustManager {
public void checkClientTrusted(X509Certificate[] arg0, String arg1) {}
public void checkServerTrusted(X509Certificate[] arg0, String arg1) {}
public X509Certificate[] getAcceptedIssuers() { return null; }
}
}
SampleMain.java
import java.io.*;
import java.net.*;
/**
* Created by Cookie on 16/8/9.
*/
public class SampleMain {
public static void main(String[] args) throws IOException {
URLConnection conn = new URL("https://74.125.203.94/").openConnection();
/** Modify connection */
TrustModifier.trust(conn);
String inputLine;
try(InputStreamReader stream = new InputStreamReader(conn.getInputStream());
BufferedReader in = new BufferedReader(stream)) {
while ((inputLine = in.readLine()) != null) {
System.out.println(inputLine);
}
}
}
}
Output
在 Output 中可以看出成功拿到了一段內容並未出現例外,連線成功
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="http://www.google.com/">here</A>.
</BODY></HTML>