繼上次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溝通有兩種寫法,使用HttpsURLConnection或HttpClient
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; } }
Place your comment