2012-11-20 15 views
10

मुझे एक अवैध SSL प्रमाणपत्र के साथ वेब सर्वर पर होस्ट की गई HTTP सेवा को कॉल करना होगा। देव में, मैं कीटोल के साथ प्रमाण पत्र आयात कर रहा हूं लेकिन प्रमाण पत्र प्रत्येक क्लाइंट इंस्टॉल पर अलग होगा, इसलिए मैं इसे केवल बंडल नहीं कर सकता।जावा में SSL सत्यापन को अनदेखा करना

प्रस्तावना: I DO पता है कि एसएसएल सत्यापन छोड़ना वास्तव में बदसूरत है। इस विशिष्ट मामले में, मुझे एसएसएल की आवश्यकता नहीं होगी और सिस्टम में अन्य सभी संचार सरल HTTP से अधिक हैं। इसलिए मुझे वास्तव में एमआईटीएम हमलों या इस तरह की परवाह नहीं है। एक हमलावर को एसएसएल तोड़ने के लिए जाने की आवश्यकता नहीं होगी क्योंकि डेटा के लिए कोई एसएसएल नहीं है। यह एक विरासत प्रणाली के लिए समर्थन है जिस पर मेरा कोई नियंत्रण नहीं है।

मैं HttpURLConnection का उपयोग SSLSocketFactory के साथ कर रहा हूं जिसमें NaiveTrustManager और NaiveHostnameVerifier है। यह कुछ स्वयं-हस्ताक्षरित सर्वरों पर काम करता है जो मैंने कोशिश की लेकिन ग्राहक की साइट पर नहीं। त्रुटि मैं हो रही है:

javax.net.ssl.SSLKeyException: [Security:090477]Certificate chain received from xxxxxxxxxx was not trusted causing SSL handshake failure. 
    at com.certicom.tls.interfaceimpl.TLSConnectionImpl.fireException(Unknown Source) 
    at com.certicom.tls.interfaceimpl.TLSConnectionImpl.fireAlertSent(Unknown Source) 
    at com.certicom.tls.record.handshake.HandshakeHandler.fireAlert(Unknown Source) 
    at com.certicom.tls.record.handshake.HandshakeHandler.fireAlert(Unknown Source) 
    at com.certicom.tls.record.handshake.ClientStateReceivedServerHello.handle(Unknown Source) 
    at com.certicom.tls.record.handshake.HandshakeHandler.handleHandshakeMessage(Unknown Source) 
    at com.certicom.tls.record.handshake.HandshakeHandler.handleHandshakeMessages(Unknown Source) 
    at com.certicom.tls.record.MessageInterpreter.interpretContent(Unknown Source) 
    at com.certicom.tls.record.MessageInterpreter.decryptMessage(Unknown Source) 
    at com.certicom.tls.record.ReadHandler.processRecord(Unknown Source) 
    at com.certicom.tls.record.ReadHandler.readRecord(Unknown Source) 
    at com.certicom.tls.record.ReadHandler.readUntilHandshakeComplete(Unknown Source) 
    at com.certicom.tls.interfaceimpl.TLSConnectionImpl.completeHandshake(Unknown Source) 
    at com.certicom.tls.record.WriteHandler.write(Unknown Source) 
    at com.certicom.io.OutputSSLIOStreamWrapper.write(Unknown Source) 
    at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:65) 
    at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:123) 
    at java.io.FilterOutputStream.flush(FilterOutputStream.java:123) 
    at weblogic.net.http.HttpURLConnection.writeRequests(HttpURLConnection.java:154) 
    at weblogic.net.http.HttpURLConnection.getInputStream(HttpURLConnection.java:358) 
    at weblogic.net.http.SOAPHttpsURLConnection.getInputStream(SOAPHttpsURLConnection.java:37) 
    at weblogic.net.http.HttpURLConnection.getResponseCode(HttpURLConnection.java:947) 
    at (my own code) 

मेरे SimpleSocketFactory लगता है:

public static final SSLSocketFactory getSocketFactory() 
{ 
    if (sslSocketFactory == null) { 
     try { 
      // get ssl context 
      SSLContext sc = SSLContext.getInstance("SSL"); 

      // Create a trust manager that does not validate certificate chains 
      TrustManager[] trustAllCerts = new TrustManager[]{ 
       new NaiveTrustManager() { 
        public java.security.cert.X509Certificate[] getAcceptedIssuers() { 
         log.debug("getAcceptedIssuers"); 
         return new java.security.cert.X509Certificate[0]; 
        } 
        public void checkClientTrusted(
         java.security.cert.X509Certificate[] certs, String authType) { 
         log.debug("checkClientTrusted"); 
        } 
        public void checkServerTrusted(
         java.security.cert.X509Certificate[] certs, String authType) { 
         log.debug("checkServerTrusted"); 
        } 
       } 
      }; 

      sc.init(null, trustAllCerts, new java.security.SecureRandom()); 
      // EDIT: fixed the following line that was redeclaring SSLSocketFactory sslSocketFactory, returning null every time. Same result though. 
      sslSocketFactory = sc.getSocketFactory(); 

      HttpsURLConnection.setDefaultSSLSocketFactory(sslSocketFactory); 
      // EDIT: The following line has no effect 
      //HttpsURLConnection.setDefaultHostnameVerifier(new NaiveHostNameVerifier()); 

     } catch (KeyManagementException e) { 
      log.error ("No SSL algorithm support: " + e.getMessage(), e); 
     } catch (NoSuchAlgorithmException e) { 
      log.error ("Exception when setting up the Naive key management.", e); 
     } 
    } 
    return sslSocketFactory; 
} 

NaiveHostnameVerifier वैध मेजबान को सीमित करने के लिए एक रास्ता है, लेकिन यह अशक्त बचा है, तो मूल रूप से कुछ भी स्वीकार करने:

public class NaiveHostnameVerifier implements HostnameVerifier { 
    String[] patterns; 

    public NaiveHostnameVerifier() { 
     this.patterns=null; 
    } 

    public NaiveHostnameVerifier (String[] patterns) { 
     this.patterns = patterns; 
    } 

    public boolean verify(String urlHostName,SSLSession session) { 
     if (patterns==null || patterns.length==0) { 
      return true; 
     } else { 
      for (String pattern : patterns) { 
       if (urlHostName.matches(pattern)) { 
        return true; 
       } 
      } 
      return false; 
     } 
    } 
} 

उपयोग इस तरह है:

try { 
     conn = (HttpURLConnection)url.openConnection(); 
     if (conn instanceof HttpsURLConnection) { 
       ((HttpsURLConnection)conn).setSSLSocketFactory(SimpleSSLSocketFactory.getSocketFactory()); 
       // EDIT: added this line, the HV has to be set on connection, not on the factory. 
       ((HttpsURLConnection)conn).setHostnameVerifier(new NaiveHostnameVerifier()); 
     } 
     conn.setDoInput(true); 
     conn.setDoOutput(true); 
     conn.setRequestMethod("POST"); 
     conn.setRequestProperty("Content-type","application/x-www-form-urlencoded"); 
     conn.connect(); 

     StringBuffer sbContent = new StringBuffer(); 
     // (snip) 
     DataOutputStream stream = new DataOutputStream(conn.getOutputStream()); 
     stream.writeBytes(sbContent.toString()); 
     stream.flush(); 
     stream.close(); 
    } catch (ClassCastException e) { 
     log.error("The URL does not seem to point to a HTTP connection"); 
     return null; 
    } catch (IOException e) { 
     log.error("Error accessing the requested URL", e); 
     return null; 
    } 

जब मैं त्रुटि संदेश पर खोज कर रहा हूं, तो अधिकांश लोग केवल अपने स्टोर में प्रमाण पत्र आयात करते हैं लेकिन फिर से, मैं वास्तव में ऐसा नहीं कर सकता क्योंकि मुझे नहीं पता कि यह कौन सा प्रमाण पत्र होगा। मेरा एकमात्र विकल्प अगर यह काम नहीं करता है तो ऐसा टूल बनाना है जो प्रमाण पत्र डाउनलोड कर सके और क्रिप्टिक कमांड लाइनों को आसानी से जोड़ सके, लेकिन मैं अपने जावा कोड को अमान्य प्रमाणपत्र को अनदेखा कर दूंगा।

कोई विचार?

+4

क्या आपको पता है कि प्रमाणपत्र (और होस्ट नाम) सत्यापन को अनदेखा करने से संभावित एमआईटीएम हमलों के कनेक्शन खुलते हैं? अगर आपको प्रमाणपत्र त्रुटियों को अनदेखा करना है तो आपकी (प्रशासनिक) सुरक्षा प्रक्रियाओं में कोई दोष दिखता है। इसके अतिरिक्त, आपको Certicom TLS विकल्पों को देखना चाहिए, क्योंकि आप स्पष्ट रूप से डिफ़ॉल्ट JSSE प्रदाता का उपयोग नहीं कर रहे हैं। – Bruno

+0

मैं एमआईटीएम हमलों के बारे में अच्छी तरह से जानता हूं। वास्तव में, अगर कोई उस नेटवर्क पर एमआईटीएम हमला करने में सक्षम है, तो संचार से हस्तक्षेप करने की तुलना में हमारे पास बहुत बड़ी समस्याएं हैं। सबसे पहले, मैं सॉफ़्टवेयर में एक कदम पर विचार कर रहा था जहां हम प्रमाण पत्र पुनर्प्राप्त करते हैं और यदि उपयोगकर्ता द्वारा सत्यापित किया जाता है, तो इसे और उपयोग के लिए स्टोर करें। हालांकि, छोटी समस्या की तुलना में यह एक बड़ी चुनौती है जिसे मैं संबोधित करने की कोशिश कर रहा हूं। मुझे Certicom TLS विकल्पों पर एक नज़र डालेंगे। –

+2

वेबलॉगिक ने एसएसएल के साथ भयानक, भयानक चीजें की हैं, और मैं आपको इससे निपटने की कोशिश करने के लिए करुणा करता हूं। वे जावा मानकों का पालन नहीं करते हैं, उनके पास सब कुछ खराब करने का अपना खराब और टूटा तरीका है। – erickson

उत्तर

2

वास्तव में उपरोक्त कोड के साथ कुछ भी गलत नहीं है। समस्या वेबलॉगिक और यह प्रमाणिक टीएलएस मॉड्यूल के साथ झूठ बोलती है। जब मैं सर्वर पर विकल्प, एसएसएल और उन्नत मुझे लगता है कि मैं एक कस्टम HostnameVerifier (SSLMBean.HostnameVerifier) ​​लेकिन केवल प्रमाण पत्र सत्यापन के साथ हस्तक्षेप करने की क्षमता का सुझाव दे तत्व हटा दिया गया है निर्दिष्ट कर सकते हैं देखो।

मैंने उपरोक्त कोड वेबलॉगिक के बाहर की कोशिश की और यह खूबसूरती से काम किया (हालांकि पोस्ट में होस्टनाम सत्यापनकर्ता को ठीक किया गया)।

फिर मैंने वेबोलिक पैरामीटर में "-DUseSunHttpHandler = true" जोड़ने की कोशिश की, जैसा कि this other question में ipolevoy द्वारा सुझाया गया है। यह काम करना शुरू कर दिया।

कहा जा रहा है कि, ओरेकल सेवा बस सर्वर पर HTTP हैंडलर को स्विच करना थोड़ा जोखिम भरा लगता है। कुछ हफ्तों के समय में मुझे काटने के लिए वापस आने वाले साइड इफेक्ट्स हो सकते हैं ...

मैंने अपने स्वयं के ट्रस्टस्टोर को परिभाषित करने का प्रयास किया और इसे एक जेएससीकैर्ट में इंगित करने की कोशिश की जिसमें आवश्यक कुंजी थी। इसे वेबलॉगिक द्वारा भी अनदेखा किया गया था क्योंकि इसमें प्रत्येक सर्वर के लिए ट्रस्टस्टोर की अपनी सेटिंग है। इसलिए मैं व्यवस्थापक से पूछता हूं कि मैन्युअल रूप से आवश्यक कुंजी आयात करें या वेबलॉग को अपने स्टोर में इंगित करें।

+0

वैसे, मैंने अभी पता चला है कि होस्टनाम वीरिफायर को या तो अनुकूलित नहीं किया जा सका और "javax.net.ssl.SSLKeyException: [सुरक्षा: 090504] में विफल रहा है: intranet.company.com से प्राप्त प्रमाणपत्र श्रृंखला - xxxx विफल होस्टनाम सत्यापन जांच। प्रमाणपत्र निहित * .company.com लेकिन अपेक्षित intranet.company.com की जांच करें "। वेबलॉगिक, मैं तुमसे नफरत करता हूं। मैं सच में है। –

0

असल में, यह 10.3 से नीचे वेबलॉगिक संस्करणों में एक बग है।5, जिसके लिए ओरेकल से पैच उपलब्ध है। विवरण के लिए कृपया मेरे ओरेकल समर्थन में दस्तावेज़ 1474 9 8 9 .1 देखें।

उपरोक्त फिक्स ओरेकल द्वारा एक अनुशंसित (लेकिन समर्थित) कामकाज है, जो काम करेगा, लेकिन पसंदीदा समाधान नहीं है।

पसंदीदा समाधान ओरेकल आलेख में वर्णित पैच को डाउनलोड करना है, और एसएसएल होस्टनाम सत्यापनकर्ता को नए के साथ प्रतिस्थापित करना जो वेबलॉगिक 10.3.5 और उससे ऊपर का हिस्सा है। यदि आप समर्थन के मामले में ओरेकल के साथ अनुपालन करना चाहते हैं, तो यह रास्ता तय करना है।

संबंधित मुद्दे