顯示具有 Https 標籤的文章。 顯示所有文章
顯示具有 Https 標籤的文章。 顯示所有文章

2018年3月31日 星期六

Java - HTTPS 檢查證書的安全連線


如何在JDK1.5中支援TLSv1.2這篇文章中,有講到如何對TLSv1.2的server進行HTTPS request,但這只是最簡單的實作例子,沒有考慮到憑證安全的檢查,如果被例如中間人攻擊的話,可能會連線請求中間被竄改了資料而不自知。

在前例中,可以看到在自訂的TrustManager 中,所有的method (getAcceptedIssuers(), checkServerTrusted(), checkClientTrusted())都沒有被實作內容,
如果發生了中間人攻擊,也就是在client端和server端的連線中間被某中間人攔截,
這時中間人可能會修改某些資料偽裝server端回傳資料給我們(client)端,
如果我們沒有對其憑證進行檢查的話,可能就無法察覺此攻擊了。

尤其是行動裝置的場合,例如手機在連到了駭客分享的wifi,程式如果不檢查HTTPS連線有無被劫持,就很容昜造成資安問題。

經過了查詢資料及自行實作後,我在這邊提供一個如何對 HTTPS 的 憑證進行驗證的方法。


  1. 為了簡單化,我使用JDK1.8,跟JDK1.5不同,JDK1.8支持TLSv1.2,
    所以不用跟上一篇文(如何在JDK1.5中支援TLSv1.2) 一樣使用BoncyCastle。
    並且把Excpetion全部throws出去,不用try-catch來使程式碼較為清晰。

    Note:
    其實JDK1.8在對TLSv1.2連線時,是不用自已建立TrustManager的,並且自己就會檢查憑證,並在檢查憑證有問題時拋出錯誤。
    但是要注意如果自己建立了TrustManager來用在連線中,卻不檢查憑證的話,在憑證有問題時是不會拋出錯誤的。
    而JDK1.5因為要使用BoncyCastle並會需要自已建立TrustManager,所以就要特別使用檢查憑證的TrustManager。
  2. 我們可以使用封包監測工具,例如Fiddler,來模擬中間人攻擊,如果我們把Java的HTTPS request 掛上Proxy,讓連線中間經過Fiddler的話,相當於就是Fiddler當了中間人,這時對使用了沒有進行憑證檢查的TrustManager的Java程式,是不會發現有任何異狀的。

步驟:

  1. 這裡要連的實驗對像跟之前一樣是號稱只支持TLSv1.2的fancyssl網站,首先去此網站上下載憑證。
    下載方式如下圖,按下F12打開開發者console後,選Security --> View Certificate --> 詳細資料 --> 複制到檔案。
  2. 使用java的工具 keytool 加入憑證到你要的憑證檔案中
    keytool -import -alias {別名} -keystore {要被放入憑證的憑證檔} -file {從網站上下載的憑證}
    例如:
    keytool -import -alias fancyssl -keystore D:\test_cer -file D:\fancyssl_cer.cer
    之後會要你打密碼,第一次產生憑證檔自己取。如果是本來就有的檔案通常密碼沒改就是預設 : changeit
  3. 接下來我展示在Java1.8下的三種寫法:
    1. HttpsTest_notSafe.java
      (自己建立的,沒有檢查憑證的TrustManager)
      import java.io.BufferedReader;
      import java.io.File;
      import java.io.FileInputStream;
      import java.io.IOException;
      import java.io.InputStream;
      import java.io.InputStreamReader;
      import java.net.HttpURLConnection;
      import java.net.MalformedURLException;
      import java.net.URL;
      import java.security.KeyManagementException;
      import java.security.KeyStore;
      import java.security.KeyStoreException;
      import java.security.NoSuchAlgorithmException;
      import java.security.NoSuchProviderException;
      import java.security.SecureRandom;
      import java.security.cert.Certificate;
      import java.security.cert.CertificateException;
      import java.security.cert.CertificateFactory;
      import java.security.cert.X509Certificate;
      
      import javax.net.ssl.HostnameVerifier;
      import javax.net.ssl.HttpsURLConnection;
      import javax.net.ssl.SSLContext;
      import javax.net.ssl.SSLSession;
      import javax.net.ssl.TrustManager;
      import javax.net.ssl.TrustManagerFactory;
      import javax.net.ssl.X509TrustManager;
      
      public class HttpsTest_notSafe {
      
       public static void main(String[] args)
         throws NoSuchAlgorithmException, KeyManagementException, MalformedURLException, IOException, NoSuchProviderException, KeyStoreException, CertificateException {
        // 將request導向 Fiddler (127.0.0.1:8888) 可模擬中間人攻擊
        System.setProperty("http.proxyHost", "127.0.0.1");
        System.setProperty("http.proxyPort", "8888");
        System.setProperty("https.proxyHost", "127.0.0.1");
        System.setProperty("https.proxyPort", "8888");
        //
        
        // 自訂的TrustManager,沒有檢查憑證,不安全
        TrustManager trustManager = new X509TrustManager() {
         public X509Certificate[] getAcceptedIssuers() {
          return new X509Certificate[0];
         }
         public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
          // do nothing
         }
         public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
          // do nothing
         }
        };
      
        SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
        // 自訂的TrustManager,沒有檢查憑證,不安全
        sslContext.init(null, new TrustManager[] { trustManager }, new SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
        
        HttpsURLConnection httpsUrlConnection = (HttpsURLConnection) (new URL("https://fancynossl.hboeck.de/")).openConnection();
        httpsUrlConnection.connect();
      
        // 印出Response
        printFromInputStream(httpsUrlConnection.getInputStream());
        
        httpsUrlConnection.disconnect();
        
       }
       
       static void printFromInputStream(InputStream in) throws IOException {
        BufferedReader responseBufferedReader = new BufferedReader((new InputStreamReader(in)));
        StringBuffer responseTextStringBuffer = new StringBuffer();
        String tempString = null;
        while ((tempString = responseBufferedReader.readLine()) != null) {
         responseTextStringBuffer.append(tempString + "\n");
        }
        String responseText = responseTextStringBuffer.toString();
        System.out.println(responseText);
       }
      }
    2. HttpsTest_safe1.java
      (JDK1.8 直接使用自帶TLSv1.2的https支持,不用建立TrustManager)
      import java.io.BufferedReader;
      import java.io.File;
      import java.io.FileInputStream;
      import java.io.IOException;
      import java.io.InputStream;
      import java.io.InputStreamReader;
      import java.net.HttpURLConnection;
      import java.net.MalformedURLException;
      import java.net.URL;
      import java.security.KeyManagementException;
      import java.security.KeyStore;
      import java.security.KeyStoreException;
      import java.security.NoSuchAlgorithmException;
      import java.security.NoSuchProviderException;
      import java.security.SecureRandom;
      import java.security.cert.Certificate;
      import java.security.cert.CertificateException;
      import java.security.cert.CertificateFactory;
      import java.security.cert.X509Certificate;
      
      import javax.net.ssl.HostnameVerifier;
      import javax.net.ssl.HttpsURLConnection;
      import javax.net.ssl.SSLContext;
      import javax.net.ssl.SSLSession;
      import javax.net.ssl.TrustManager;
      import javax.net.ssl.TrustManagerFactory;
      import javax.net.ssl.X509TrustManager;
      
      public class HttpsTest_safe1 {
      
       public static void main(String[] args) throws NoSuchAlgorithmException, KeyManagementException, MalformedURLException, IOException, NoSuchProviderException, KeyStoreException, CertificateException {
        // 將request導向 Fiddler (127.0.0.1:8888) 可模擬中間人攻擊
        System.setProperty("http.proxyHost", "127.0.0.1");
        System.setProperty("http.proxyPort", "8888");
        System.setProperty("https.proxyHost", "127.0.0.1");
        System.setProperty("https.proxyPort", "8888");
        //
      
        //建立連線
        HttpsURLConnection httpsUrlConnection = (HttpsURLConnection) (new URL("https://fancynossl.hboeck.de/")).openConnection();
        httpsUrlConnection.connect();
      
        // 印出Response
        printFromInputStream(httpsUrlConnection.getInputStream());
        
        httpsUrlConnection.disconnect();  
       }
       
       static void printFromInputStream(InputStream in) throws IOException {
        BufferedReader responseBufferedReader = new BufferedReader((new InputStreamReader(in)));
        StringBuffer responseTextStringBuffer = new StringBuffer();
        String tempString = null;
        while ((tempString = responseBufferedReader.readLine()) != null) {
         responseTextStringBuffer.append(tempString + "\n");
        }
        String responseText = responseTextStringBuffer.toString();
        System.out.println(responseText);
       }
      }
    3. HttpsTest_safe2.java
      (自已建立的,使用憑證檔產生出TrustManager)
      import java.io.BufferedReader;
      import java.io.File;
      import java.io.FileInputStream;
      import java.io.IOException;
      import java.io.InputStream;
      import java.io.InputStreamReader;
      import java.net.HttpURLConnection;
      import java.net.MalformedURLException;
      import java.net.URL;
      import java.security.KeyManagementException;
      import java.security.KeyStore;
      import java.security.KeyStoreException;
      import java.security.NoSuchAlgorithmException;
      import java.security.NoSuchProviderException;
      import java.security.SecureRandom;
      import java.security.cert.Certificate;
      import java.security.cert.CertificateException;
      import java.security.cert.CertificateFactory;
      import java.security.cert.X509Certificate;
      
      import javax.net.ssl.HostnameVerifier;
      import javax.net.ssl.HttpsURLConnection;
      import javax.net.ssl.SSLContext;
      import javax.net.ssl.SSLSession;
      import javax.net.ssl.TrustManager;
      import javax.net.ssl.TrustManagerFactory;
      import javax.net.ssl.X509TrustManager;
      
      public class HttpsTest_safe2 {
      
       public static void main(String[] args)
         throws NoSuchAlgorithmException, KeyManagementException, MalformedURLException, IOException, NoSuchProviderException, KeyStoreException, CertificateException {
        // 將request導向 Fiddler (127.0.0.1:8888) 可模擬中間人攻擊
        System.setProperty("http.proxyHost", "127.0.0.1");
        System.setProperty("http.proxyPort", "8888");
        System.setProperty("https.proxyHost", "127.0.0.1");
        System.setProperty("https.proxyPort", "8888");
        //  
        
              //從憑證產生TrustManager
              String password = "changeit";  //預設密碼為changeit
              //讀取憑證
              File file = new File("D:/test_cer");
              //通常會將憑證都加到%Java_Home%/lib/security/cacerts/中
              //File file = new File(System.getProperty("java.home") + "/lib/security/cacerts");
              InputStream in = new FileInputStream(file);
              KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
              keyStore.load(in, password.toCharArray());
              in.close();
              //建立TrustManager
              TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509", "SunJSSE");
              trustManagerFactory.init(keyStore);
      
        SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
        sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
      
        HttpsURLConnection httpsUrlConnection = (HttpsURLConnection) (new URL("https://fancynossl.hboeck.de/")).openConnection();
        httpsUrlConnection.connect();
      
        // 印出Response
        printFromInputStream(httpsUrlConnection.getInputStream());
        
        httpsUrlConnection.disconnect();
        
       }
       
       static void printFromInputStream(InputStream in) throws IOException {
        BufferedReader responseBufferedReader = new BufferedReader((new InputStreamReader(in)));
        StringBuffer responseTextStringBuffer = new StringBuffer();
        String tempString = null;
        while ((tempString = responseBufferedReader.readLine()) != null) {
         responseTextStringBuffer.append(tempString + "\n");
        }
        String responseText = responseTextStringBuffer.toString();
        System.out.println(responseText);
       }
      }
我們可以打開 Fiddler,並在 Tools --> Options --> HTTPS,勾選 "Decrypt HTTPS traffic 設定攔截 HTTPS request 模擬中間人,
並且在上述的三個Java程式中,對設定Proxy的程式碼註解或不註解來測試。
可以發現以下結果:
有拋出錯誤沒有拋出錯誤有拋出錯誤沒有拋出錯誤
有經過Fiddler沒有經過Fiddler
HttpsTest_notSafe.java沒有拋出錯誤沒有拋出錯誤
HttpsTest_safe1.java有拋出錯誤沒有拋出錯誤
HttpsTest_safe2.java有拋出錯誤沒有拋出錯誤

可以看到,如果是JDK1.8如果使用了自帶TLSv1.2的支持寫法,即不自己建立TrustManager的話,程式是可以自行檢查出憑證錯誤的。

但如果使用了自已建立的TrustManager時,就要使用有檢查憑證的TrustManager才行,此篇文章使用的是由憑證檔產生TrustManager。
除了由憑證檔產生TrustManager以外,也可由自己撰寫檢查憑證相關的TrustManager method ((getAcceptedIssuers(), checkServerTrusted(), checkClientTrusted())) 。

原始碼下載:
HttpsTest.7z

參考資料
  1. Java 使用自签证书访问https站点
  2. 苹果核 - Android App 安全的HTTPS 通信
  3. Sun Java System Application Server Enterprise Edition 8.2 管理指南
  4. Java Keytool的使用及申請憑證(以Microsoft Active Directory Certificate Services為例)
  5. java中 SSL认证和keystore使用

2018年3月20日 星期二

如何在JDK1.5中支援TLSv1.2

使用Java 傳 HTTPS request 時,如果接收端的server (例如別家公司開放的web api)是只使用 TLSv1.2 時,可能會因為舊版的 jdk 沒有支援,而造成連線錯誤。

如果是使用 JDK1.8,其支持 TLSv1.2,並且且預設就使用 TLSv1.2 來進行 HTTPS 的連線,
寫法可以參考之前寫的這篇文章 "以Java 由Url下載圖片" 裡面的 "getHttpURLConnectionFromHttps()" 方法來進行 HTTPS 的請求。

但是例如如果為較舊的 JDK1.5,則沒有支持 TLSv1.2,此時還用 JDK1.8的寫法去請求 TLSv1.2的server時,就會產生錯誤。

在這篇文章中,我紀錄了我找到的方法,如何讓 JDK1.5 也能進行對 TLSv1.2 server的請求。

=================================

我使用的JDK為 jdk1.5.0_22
測試的網站為 https://fancyssl.hboeck.de/
此網站聲稱只為TLSv1.2的request開放
可以使用線上SSL檢測工具來查看此網站的SSL相關設定
https://www.ssllabs.com/ssltest/analyze.html?d=fancyssl.hboeck.de

需要的 jar

  1. Bouncy Castle 的 Library : 
    1. Provider 
    2. DTLS/TLS API/JSSE Provider
  2. 解開Java密鑰長度限制的
    "Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files"
    1. JDK 1.5 可到這裡下載 "Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 5.0"。


步驟:

  1. 導入Bouncy Castle的 jar
    Bouncy Castle 是一個提供許多密碼演法等的 Java Library,而 TLSv1.2 跟 舊版的差別其中就有密碼演算等不同,其中更深的原理我沒有鑽研,在此只展示找到的可行解決方案。

    首先先到 Bouncy Castle官網 下載 Provider 及 DTLS/TLS API/JSSE Provider 的 jar 檔,我這邊選擇的為 bcprov-jdk15on-159.jarbctls-jdk15on-159.jar。 請下載並加到 Java 專案的 Library中。
  2. 測試程式進對指定的url進行TLSv1.2 HTTPS 請求,並將回應印出來,在這裡會將整個網頁的源始碼印出來。

    測試程式碼如下:
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.security.SecureRandom;
    import java.security.Security;
    import java.security.cert.CertificateException;
    import java.security.cert.X509Certificate;
    
    import javax.net.ssl.HostnameVerifier;
    import javax.net.ssl.HttpsURLConnection;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLSession;
    import javax.net.ssl.TrustManager;
    import javax.net.ssl.X509TrustManager;
    
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider;
    
    public class HttpsClientRequestTest {
    
        public static void main(String[] args)
                throws Exception
            {
                Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
                Security.insertProviderAt(new BouncyCastleProvider(), 1);
    
                Security.removeProvider(BouncyCastleJsseProvider.PROVIDER_NAME);
                Security.insertProviderAt(new BouncyCastleJsseProvider(), 2);
    
                /*
                 * TEST CODE ONLY. If writing your own code based on this test case, you should configure
                 * your trust manager(s) using a proper TrustManagerFactory, or else the server will be
                 * completely unauthenticated.
                 */
                TrustManager tm = new X509TrustManager()
                {
                    public X509Certificate[] getAcceptedIssuers()
                    {
                        return new X509Certificate[0];
                    }
    
                    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException
                    {
                     //do nothing
                    }
    
                    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException
                    {
                     //do nothing
                    }
                };
                
                HostnameVerifier customHostnameVerifier = new HostnameVerifier() {
                     public boolean verify(String arg0, SSLSession arg1) {        
                          return true;
                     }
                };
    
                SSLContext sslContext = SSLContext.getInstance("TLSv1.2", BouncyCastleJsseProvider.PROVIDER_NAME);
                sslContext.init(null, new TrustManager[]{ tm }, new SecureRandom());
                HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
                HttpsURLConnection.setDefaultHostnameVerifier(customHostnameVerifier);
                
                HttpURLConnection httpUrlConnection = (HttpURLConnection) (new URL("https://fancynossl.hboeck.de")).openConnection();
                
                httpUrlConnection.setRequestProperty("User-Agent", "Mozilla/5.0 (Linux; Android 4.2.1; Nexus 7 Build/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166  Safari/535.19");
                httpUrlConnection.connect();
    
                InputStream is = null;
         if (httpUrlConnection.getResponseCode() >= 400) {  
             is = httpUrlConnection.getErrorStream();  
         } else {  
             is = httpUrlConnection.getInputStream();  
         }
          
                BufferedReader responseBufferedReader = new BufferedReader((new InputStreamReader(is)));
                StringBuffer responseTextStringBuffer = new StringBuffer();
                String tempString = null;
                while((tempString = responseBufferedReader.readLine()) != null) {
                    responseTextStringBuffer.append(tempString + "\n");
                }
                String responseText = responseTextStringBuffer.toString();
                httpUrlConnection.disconnect();
          
                System.out.println(responseText);
            }
    }
    
  3. 因為還沒有開放 Java 的密鑰長度限制,所以應該會出現以下錯誤java.security.InvalidKeyException: Illegal key sizeException
    此時將下載的 "Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 5.0" 裡面的 "local_policy.jar" 和 "US_export_policy.jar" 覆蓋到JAVA_HOME\jre\lib\security\ 之下的 "local_policy.jar" 和 "US_export_policy.jar" ,再執行一次,應該就會成功了。
    下載頁面如圖所示:
    程式成功時輸出如圖,可以看到網頁的html源始碼被印了出來 (Eclipse):



參考資料:
  1. java.lang.IllegalArgumentException: TLSv1.2 on JRE 1.5
  2. The Legion of the Bouncy Castle
  3. bcgit/bc-java
  4. 解决java.io.IOException: HTTPS hostname wrong: should be
  5. AES加密时抛出java.security.InvalidKeyException: Illegal key size or default parameters

2017年10月11日 星期三

以Java 由Url下載圖片

今天要來記錄如何使用Java來下載網路上的圖片(或檔案,此例只下載圖片),

Java可以對Url進行Http Request來取得Response,
得到input stream後將檔案儲存下來,

為了避免有些Server會擋程式的Request,
我們必須模仿瀏覽器,在Request中加上User-Agent的Header (或更多的其他Header,模仿的越像越不容易被擋),

如果圖片的Url是http的話比較簡單,
但如果是https的話,即SSL,那就要取得對方Server網站的憑證,
或是自己實作一個 X509TrustManager,來所有憑證檢查都通過,

如果是JDK 1.8 以下,可能會有此Exception :
Could not generate DH keypair
使用 JDK 1.8 就可解決此問題,
可參考 [Java] 處理無法透過SSL抓取網站資料的問題

以下為程式碼範例,說明都寫在註解中:


import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

public class ImageDownloader {

 public static void main(String[] args) {

  String fileName_http = downloadImageFromUrl("http://www.image.com/files/8813/5551/7470/cruise-ship.png","D:" + File.separator, "HttpImgTest");
  System.out.println("Http的圖片下載: " + fileName_http);
  
  String fileName_https = downloadImageFromUrl("https://upload.wikimedia.org/wikipedia/commons/thumb/e/ea/Plithocyon_armagnacensis.JPG/220px-Plithocyon_armagnacensis.JPG","D:" + File.separator, "HttpsImgTest");
  System.out.println("Https的圖片下載: " + fileName_https);

 }

 public static String downloadImageFromUrl(String url, String fileDirectoryPath, String fileNameWithoutFormat) {
  String filePath = null;
  
  BufferedInputStream in = null;
  ByteArrayOutputStream out = null;
  HttpURLConnection httpUrlConnection = null;
  FileOutputStream file = null;

  try {
   
   if (url.startsWith("https://")) {
    //HTTPS時
    httpUrlConnection = getHttpURLConnectionFromHttps(url);
   }
   //如果不是HTTPS或是沒成功得到httpUrlConnection,用HTTP的方法
   if(httpUrlConnection == null) {
    httpUrlConnection = (HttpURLConnection) (new URL(url)).openConnection();
   }
   
   // 設置User-Agent,偽裝成一般瀏覽器,不然有些伺服器會擋掉機器程式請求
   httpUrlConnection.setRequestProperty("User-Agent",
     "Mozilla/5.0 (Linux; Android 4.2.1; Nexus 7 Build/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166  Safari/535.19");
   httpUrlConnection.connect();

   String imageType;
   if (httpUrlConnection.getResponseCode() == 200) {
    //成功取得response,
    //取得contentType
    String contentType = httpUrlConnection.getHeaderField("Content-Type");
    // 只處理image的回應
    if ("image".equals(contentType.substring(0, contentType.indexOf("/")))) {
     //得到對方Server提供的圖片副檔名,如jpg, png等
     imageType = contentType.substring(contentType.indexOf("/") + 1);

     if (imageType != null && !"".equals(imageType)) {
      //由HttpUrlConnection取得輸入串流
      in = new BufferedInputStream(httpUrlConnection.getInputStream());
      out = new ByteArrayOutputStream();

      //建立串流Buffer
      byte[] buffer = new byte[1024];

      file = new FileOutputStream(new File(fileDirectoryPath + File.separator + fileNameWithoutFormat + "." + imageType));

      int readByte;
      while ((readByte = in.read(buffer)) != -1) {
       //輸出檔案
       out.write(buffer, 0, readByte);
      }      

      byte[] response = out.toByteArray();
      file.write(response);      

      //下載成功後,返回檔案路徑
      filePath = fileDirectoryPath + File.separator + fileNameWithoutFormat + "." + imageType;
     }
    }

   }
  } catch (MalformedURLException e) {
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
  } finally {
   //關閉各種串流
   try {
    if (out != null) {
     out.close();
    }
    if (in != null) {
     in.close();
    }
    if (httpUrlConnection != null) {
     httpUrlConnection.disconnect();
    }
    if (file != null) {
     file.close();
    }
   }catch (IOException e) {
    e.printStackTrace();
   }
   
  }
  return filePath;
 }

 public static HttpURLConnection getHttpURLConnectionFromHttps(String url) {
  HttpURLConnection httpUrlConnection = null;
  //建立一個信認所有憑證的X509TrustManager,放到TrustManager裡面
  TrustManager[] trustAllCerts;
  try {
   // Activate the new trust manager
   trustAllCerts = new TrustManager[] { new X509TrustManager() {

    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {     // TODO Auto-generated method stub
     //不作任何事
    }

    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {     // TODO Auto-generated method stub
     //不作任何事
    }

    public X509Certificate[] getAcceptedIssuers() {
     //不作任何事
     return null;
    }

   } };

   //設置SSL設定
   SSLContext sslContext = SSLContext.getInstance("SSL");
   sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
   HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());

   //跟HTTP一樣,用Url建立連線
   httpUrlConnection = (HttpURLConnection) (new URL(url)).openConnection();
  } catch (KeyManagementException e) {
   e.printStackTrace();
  } catch (NoSuchAlgorithmException e) {
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
  }
  
  return httpUrlConnection;
 }

}


源碼下載:
ImageDownloaderFromHttpOrHttps.7z

參考資料: