LearnHouse

[Android]HttpsURLConnection實作HTTPs與強制允許自簽憑證(Self-Signed Certificate)

繼上次Apache伺服器憑證申請與安裝後,就可以開始implement了

這時你的Web Server已經有經過CA認可的合法憑證,且是在有效的效期內,因此可以直接參考Security with HTTPS and SSL

寫完你的APP就可以透過https和你的Server溝通了......好講解完畢,你已經可以和Server用https連線了

.
.
.

不過這裡當然不會講一般正常的情況下,而是當你沒有錢買憑證的時後,卻又想要你的app能透過https和你的server溝通

這時後又該怎麼做呢???

通常不用錢的憑證就只有自己當CA,自己產生自簽憑證(self-signed certificate)一途了

而這種情況有兩種做法來讓你的APP信任自簽憑證,一種是比較危險,另外一種是危險中比較安全一點的

為何兩個都說危險呢? 因為信任非CA認可過的憑證本身就是很危險的一件事了

但雖如此還是會有情況下是需要強制允許的 (本人就有這個需求)

而第一種危險中似乎比較安全一點的作法,我沒研究,因為我覺得很「費氣」

它的做法是把你認為合法的憑證,預先先放到你的APP裡,然後連線的時後直接拿local端的憑證去驗

所以下開始講第二種方法,也就是強制允許所有自簽憑證(很危險,請斟酌使用)

首先Android要透過https與Server溝通有兩種寫法,使用HttpsURLConnectionHttpClient

HttpsURLConnection是2.3之後才出現的package,也是Android Developer建議的新的使用方式

曾有看過一篇google裡面工程師的一篇文章,他提到舊有的HttpClient由於提供很多很細的API

每次Upgrade的時後都要費很多工來維護,而HttpsURLConnection已經提供大部分一般Programer會用到的API

因此漸漸的他們想要用HttpsURLConnection來取代HttpClient

所以本來我也想用HttpsURLConnection來實作upload,但後來發現我沒辦法及時的取得目前檔案上傳幾個byte~

因為上傳的這個動作底層都幫我做掉了,我只能把要上傳的資料塞給API,之後就不歸我管一直等到Server回應成功或失敗

但也許是我還沒找到方法取得及時的上傳API,有知道方法的網友再請指教分享一下囉~

以下還是要先說明使用HttpsURLConnection要如何才能強制允許所有自簽憑證,至於HttpClient會再另開一篇解說

我想,開始說HttpsURLConnection前也不用解釋太多,直接看Code吧:

		try{
			URL url = new URL("https://127.0.0.1/weblogin.php");
		    HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
			//AllowAllHostNameVerifier
		    HttpsURLConnection.setDefaultHostnameVerifier(new AllowAllHostNameVerifier());

		    // Create the SSL connection
		    SSLContext sc;
		    sc = SSLContext.getInstance("TLS");
		    //The following are the most important to allow self-signed certificate
		    sc.init(null, new TrustManager[] {
		    		  new X509TrustManager() {
		    			    public void checkClientTrusted(X509Certificate[] chain, String authType) {}
		    			    public void checkServerTrusted(X509Certificate[] chain, String authType) {}
		    			    public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[]{}; }
		    			  }
		    			}, null);
		    conn.setSSLSocketFactory(sc.getSocketFactory());

		    conn.setDoOutput(true);
		    conn.setDoInput(true);
		    conn.setRequestMethod("POST");
		    // set Timeout and method
		    conn.setReadTimeout(20000);
		    conn.setConnectTimeout(7000);

		    conn.setRequestProperty("Content-Length", String.valueOf(args.getBytes().length));
		    java.io.DataOutputStream dos = new java.io.DataOutputStream(conn.getOutputStream());
		    dos.writeBytes(args);

		    java.io.BufferedReader rd = new java.io.BufferedReader(new java.io.InputStreamReader(conn.getInputStream(), "utf-8"));
		    String line;
		    while ((line = rd.readLine()) != null) {
		        content.append(line);
		    }
			rd.close();

			responseContent = content.toString();
			System.out.println(responseContent);

		} catch (Exception e) {
			e.printStackTrace();
			tv.setText(e.toString());
		}

下面則是實作用來騙APP說Server端驗證沒問題的Class

	public class AllowAllHostNameVerifier implements HostnameVerifier {

	    public boolean verify(String hostname, SSLSession session) {
	        //Log.i("RestUtilImpl", "Approving certificate for " + hostname);
	    	System.out.println("RestUtilImpl Approving certificate for " + hostname);
	        return true;
	    }
	}
posted by admin in 程式&軟體 and have No Comments

Place your comment

Please fill your data and comment below.
Name
Email
Website
Your comment