2011-08-19 37 views
14

Tôi có 2 ứng dụng, một là Servlet/Tomcat Server và một là một ứng dụng Android.Android: HTTPS (SSL) kết nối bằng cách sử dụng HttpsURLConnection

Tôi muốn sử dụng HttpURLConnection để gửi và nhận XML giữa cả hai.

Code:

private String sendPostRequest(String requeststring) { 

    DataInputStream dis = null; 
    StringBuffer messagebuffer = new StringBuffer(); 

    HttpURLConnection urlConnection = null; 

    try { 
     URL url = new URL(this.getServerURL()); 

     urlConnection = (HttpURLConnection) url.openConnection();   

     urlConnection.setDoOutput(true); 

     urlConnection.setRequestMethod("POST"); 

     OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream()); 

     out.write(requeststring.getBytes()); 

     out.flush(); 

     InputStream in = new BufferedInputStream(urlConnection.getInputStream()); 

     dis = new DataInputStream(in); 

     int ch; 

     long len = urlConnection.getContentLength(); 

     if (len != -1) { 

      for (int i = 0; i < len; i++) 

       if ((ch = dis.read()) != -1) { 

        messagebuffer.append((char) ch); 
       } 
     } else { 

      while ((ch = dis.read()) != -1) 
       messagebuffer.append((char) ch); 
     } 

     dis.close(); 

    } catch (Exception e) { 

     e.printStackTrace(); 

    } finally { 

     urlConnection.disconnect(); 
    } 

    return messagebuffer.toString(); 
} 

Bây giờ, tôi cần phải sử dụng SSL để gửi XMLs để bảo mật.

Trước tiên, tôi sử dụng Keytool Java để tạo tệp .keystore.

Keytool -keygen -alias tomcat -keyalg RSA 

Sau đó, tôi đưa Bộ luật XML trên file server.xml của Tomcat để sử dụng SSL

<Connector 
port="8443" protocol="HTTP/1.1" SSLEnabled="true" 
maxThreads="150" scheme="https" secure="true" 
keystoreFile="c:/Documents and Settings/MyUser/.keystore" 
keystorePass="password" 
clientAuth="false" sslProtocol="TLS" 
/> 

Sau đó, tôi thay đổi nó trở thành HttpURLConnection cho HttpsURLConnection

private String sendPostRequest(String requeststring) { 

    DataInputStream dis = null; 
    StringBuffer messagebuffer = new StringBuffer(); 

    HttpURLConnection urlConnection = null; 

    //Conexion por HTTPS 
    HttpsURLConnection urlHttpsConnection = null; 

    try { 
     URL url = new URL(this.getServerURL()); 

     //urlConnection = (HttpURLConnection) url.openConnection();   

     //Si necesito usar HTTPS 
     if (url.getProtocol().toLowerCase().equals("https")) { 

      trustAllHosts(); 

      //Creo la Conexion 
      urlHttpsConnection = (HttpsURLConnection) url.openConnection(); 

      //Seteo la verificacion para que NO verifique nada!! 
      urlHttpsConnection.setHostnameVerifier(DO_NOT_VERIFY); 

      //Asigno a la otra variable para usar simpre la mism 
      urlConnection = urlHttpsConnection; 

     } else { 

      urlConnection = (HttpURLConnection) url.openConnection(); 
     } 

//Do the same like up 

và thêm một trustAllHosts phương pháp tin cậy mọi máy chủ (không kiểm tra bất kỳ chứng chỉ nào)

private static void trustAllHosts() { 

    X509TrustManager easyTrustManager = new X509TrustManager() { 

     public void checkClientTrusted(
       X509Certificate[] chain, 
       String authType) throws CertificateException { 
      // Oh, I am easy! 
     } 

     public void checkServerTrusted(
       X509Certificate[] chain, 
       String authType) throws CertificateException { 
      // Oh, I am easy! 
     } 

     public X509Certificate[] getAcceptedIssuers() { 
      return null; 
     } 

    }; 

    // Create a trust manager that does not validate certificate chains 
    TrustManager[] trustAllCerts = new TrustManager[] {easyTrustManager}; 

    // Install the all-trusting trust manager 
    try { 
     SSLContext sc = SSLContext.getInstance("TLS"); 

     sc.init(null, trustAllCerts, new java.security.SecureRandom()); 

     HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); 

    } catch (Exception e) { 
      e.printStackTrace(); 
    } 
} 

Những thay đổi đó hoạt động rất tốt, nhưng tôi không muốn Tin cậy mọi máy chủ. Tôi muốn sử dụng tệp kho khóa của mình để xác thực kết nối và sử dụng SSL đúng cách. Tôi đọc rất nhiều trên internet và thực hiện rất nhiều bài kiểm tra, nhưng tôi không thể hiểu những gì tôi phải làm và cách thực hiện.

Ai đó có thể giúp tôi không?

Thank you very much

Xin lỗi vì kém tiếng Anh của tôi

------------------------- CẬP NHẬT 2011/08/24 ------------------------------------------------ -

Vâng, tôi vẫn đang làm việc này. Tôi đã thực hiện một phương pháp mới để thiết lập KeyStore, InputStream, vv

Phương pháp này trông như thế này:

private static void trustIFNetServer() { 

    try { 
     TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 

     KeyStore ks = KeyStore.getInstance("BKS"); 

     InputStream in = context.getResources().openRawResource(R.raw.mykeystore); 

     String keyPassword = "password"; 

     ks.load(in, keyPassword.toCharArray()); 

     in.close(); 

     tmf.init(ks); 

     TrustManager[] tms = tmf.getTrustManagers();  

     SSLContext sc = SSLContext.getInstance("TLS"); 

    sc.init(null, tms, new java.security.SecureRandom()); 

    } catch (Exception e) { 
    e.printStackTrace(); 
    } 
} 

Trước tiên tôi đã có rất nhiều vấn đề với Key và Giấy chứng nhận, nhưng bây giờ nó đang làm việc (Tôi nghĩ vậy)

Vấn đề của tôi lúc này là Ngoại lệ thời gian. Tôi không biết tại sao nó được tạo ra. Tôi nghĩ rằng đó là một cái gì đó với các dữ liệu viết, nhưng tôi không thể giải quyết được nêu ra.

Bất kỳ ý tưởng nào?

+0

Bạn đang sử dụng một giấy chứng nhận có chữ ký của một certificate authority nổi tiếng hoặc bạn đang sử dụng một chứng chỉ tự ký? –

Trả lời

6

Bạn cần tạo tệp lưu trữ tin cậy cho chứng chỉ tự ký của mình như được mô tả here. Sử dụng nó ở phía máy khách để kết nối với máy chủ của bạn. Nó không thực sự quan trọng nếu bạn sử dụng JKS hoặc định dạng khác, tôi sẽ giả sử JKS cho bây giờ.

Để thực hiện những gì bạn có trong đầu, bạn cần có một khác biệt TrustManager. Bạn có thể sử dụng TrustManagerFactory và cung cấp các cài đặt tin cậy với cửa hàng tin cậy mới được tạo của bạn.

TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); 
KeyStore ks = KeyStore.getInstance("JKS"); 
FileInputStream in = new FileInputStream("<path to your key store>"); 
ks.load(in, "password".toCharArray()); 
in.close(); 
tmf.init(ks); 
TrustManager[] tms = tmf.getTrustManagers(); 

Sử dụng tms init SSLContext của bạn thay vì cho các thiết lập sự tin tưởng mới để được sử dụng cho kết nối/TLS SSL của bạn.

Ngoài ra, bạn nên đảm bảo rằng phần CN của chứng chỉ TLS của máy chủ bằng FQDN (tên miền đủ điều kiện) của máy chủ của bạn, ví dụ: nếu URL cơ sở máy chủ của bạn là 'https://www.example.com', thì CN của chứng chỉ phải là 'www.example.com'. Điều này là cần thiết để xác minh tên máy chủ lưu trữ, một tính năng ngăn chặn các cuộc tấn công trung gian. Bạn có thể vô hiệu hóa điều này, nhưng chỉ khi sử dụng kết nối của bạn sẽ thực sự an toàn.

+0

Tôi nghĩ rằng anh ấy cần phải định cấu hình chính xác cửa hàng của ứng dụng khách của android chứ không phải máy chủ. –

+0

Bạn hoàn toàn đúng - Tôi sẽ thay đổi điều này, cảm ơn! – emboss

+0

Cảm ơn sự giúp đỡ. Tôi sẽ cố gắng hiểu tất cả điều này và thực hiện một số xét nghiệm. Cảm ơn nhiều! –

0

Tạo cửa hàng tin cậy, lưu trữ ở dạng tài sản và sử dụng nó khởi tạo SocketFactory này. Sau đó sử dụng nhà máy thay vì của riêng bạn 'tin tưởng tất cả mọi người' một.

+0

Cảm ơn, bạn có ví dụ nào không? –

+0

Không phải là một ví dụ đầy đủ, nhưng một khi bạn đã tải bạn tin cậy lưu trữ (trong đó có chứng chỉ máy chủ), chỉ cần vượt qua nó để các nhà xây dựng cùng với mật khẩu. Sau đó, bạn có thể chuyển thể hiện 'SocketFactory' kết quả thành' HttpsURLConnection.setDefaultSSLSocketFactory() '. –

Các vấn đề liên quan