2011-08-31 14 views
35

से मेल नहीं खाता है, मैं Google की सेवा में से किसी एक से कनेक्ट करने के लिए निम्न कोड का उपयोग कर रहा हूं। इस कोड को अपने स्थानीय मशीन पर ठीक काम किया:जावा एसएसएलएक्सप्शन: प्रमाणपत्र में होस्टनाम

HttpClient client=new DefaultHttpClient(); 
HttpPost post = new HttpPost("https://www.google.com/accounts/ClientLogin"); 
post.setEntity(new UrlEncodedFormEntity(myData)); 
HttpResponse response = client.execute(post); 

मैं एक उत्पादन वातावरण है, जो Google.com को अवरुद्ध कर दिया में इस कोड डाल दिया। अनुरोध पर, उन्होंने मुझे आईपी तक पहुंचने की अनुमति देकर Google सर्वर के साथ संचार की अनुमति दी: 74.125.236.52 - जो Google के आईपी में से एक है। मैंने इस प्रविष्टि को जोड़ने के लिए अपनी मेजबान फ़ाइल भी संपादित की।

फिर भी मैं यूआरएल तक नहीं पहुंच सका, जो मुझे आश्चर्य है। इसलिए मैं के साथ ऊपर कोड की जगह:

HttpPost post = new HttpPost("https://74.125.236.52/accounts/ClientLogin"); 

अब मैं इस तरह एक त्रुटि प्राप्त:

javax.net.ssl.SSLException: प्रमाण पत्र में होस्ट नाम से मेल नहीं खाती: <74.125.236.52>! = <www.google.com>

मुझे लगता है कि इस वजह से गूगल कई आईपी है। मैं उन सभी आईपी तक पहुंचने की अनुमति देने के लिए नेटवर्क व्यवस्थापक से नहीं पूछ सकता - मुझे यह पूरी सूची भी नहीं मिल सकती है।

अब मुझे क्या करना चाहिए? क्या जावा स्तर पर कोई कामकाज है? या यह पूरी तरह से नेटवर्क लड़के के हाथों में है?

+0

SSL प्रमाणपत्र आमतौर पर एक विशिष्ट डोमेन * नाम * के साथ आता है जो इसे लागू होता है, और करने के लिए करता है, तो उस नाम से मेल नहीं खाता नाम का अनुरोध, आपका ग्राहक आपको चेतावनी देता है कि कनेक्शन सही ढंग से प्रमाणीकृत नहीं है।आप जांच सकते हैं कि क्या आपका ग्राहक आपको कनेक्शन के लिए एक स्पष्ट प्रमाणपत्र ओवरराइड निर्दिष्ट करने देता है। –

+3

यूआरएल में होस्टनाम प्रमाणपत्र में होस्टनाम से मेल खाना चाहिए। आपको मेजबान फ़ाइल के साथ काम करने का प्रयास करना चाहिए। यदि नहीं, तो आप 74.125.236.52 के लिए google.com को स्वीकार करने के लिए प्रमाण पत्र सत्यापन दिनचर्या को ओवरराइड कर सकते हैं (इसे बहुत हल्का मत बनाओ!)। – Thilo

+0

@ थिलो: सत्यापन दिनचर्या को ओवरराइड कैसे करें? – WinOrWin

उत्तर

4

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

// Do not do this in production!!! 
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier(){ 
    public boolean verify(String string,SSLSession ssls) { 
     return true; 
    } 
}); 

यह मेरे लिए ठीक लग रहा है, हालांकि मैं जानता हूँ कि इस समाधान अस्थायी है: मैं इस विधि गयी। मैं नेटवर्क लोगों के साथ काम कर रहा हूं यह पहचानने के लिए कि मेरी मेजबान फ़ाइल को क्यों नजरअंदाज किया जा रहा है।

+12

यह वास्तव में एक बुरा विचार है। वैसे, आप '/ etc/nsswitch.conf' में लुकअप ऑर्डर को सत्यापित करना चाहते हैं और देख सकते हैं कि लुकअप में होस्ट फ़ाइल को अनदेखा किया जा रहा है या नहीं। –

+0

अच्छा विचार अगर आप कुछ की तरह कर रहे हैं ... अगर (url.startsWith ("https: // स्थानीय होस्ट")) SSL अक्षम करें –

+12

कृपया के रूप में यह एक हास्यास्पद बुरा विचार है, अस्थायी या स्वीकार किए जाते हैं जवाब के रूप में इस मत छोड़ो नहीं। इस संदर्भ में आपके लिए यह ठीक हो सकता है, लेकिन अन्य लोगों के लिए सामान्यीकृत होने की संभावना नहीं है जो समान प्रश्नों के कारण इस प्रश्न को ढूंढते हैं। आप एसएसएल का भी उपयोग नहीं कर सकते हैं, कम से कम उस मामले में आप सुरक्षा के बारे में किसी से भी मजाक नहीं कर रहे हैं। एक बार जब आप निष्कर्ष निकालेंगे और वास्तव में समस्या को अपने बारे में बताएंगे (आपके नेटवर्क लोगों के साथ वार्ता के बाद) और केवल इसे स्वीकार करें। – roguesys

22

प्रमाण पत्र सत्यापन प्रक्रिया हमेशा सर्वर द्वारा प्रस्तुत प्रमाणपत्र के DNS नाम को सत्यापित करेगी, क्लाइंट द्वारा उपयोग किए गए यूआरएल में सर्वर के होस्टनाम के साथ।

निम्नलिखित कोड

HttpPost post = new HttpPost("https://74.125.236.52/accounts/ClientLogin"); 

प्रमाण पत्र सत्यापन प्रक्रिया की पुष्टि करने कि सर्वर द्वारा जारी किए गए प्रमाण पत्र है, यानी www.google.com का सामान्य नाम होस्ट नाम अर्थात 74.125.236.52 से मेल खाता है का परिणाम देगा। जाहिर है, यह विफलता के परिणामस्वरूप बाध्य है (आप ब्राउजर के साथ यूआरएल https://74.125.236.52/accounts/ClientLogin पर ब्राउज़ करके इसे सत्यापित कर सकते थे, और परिणामी त्रुटि स्वयं को देखा)।

माना जाता है कि, सुरक्षा के लिए, आप अपना खुद का TrustManager लिखने में संकोच नहीं करते हैं (और जब तक आप एक सुरक्षित लिखने के बारे में समझ नहीं लेते हैं), तो आपको यह सुनिश्चित करने के लिए अपने डेटासेंटर में DNS रिकॉर्ड्स स्थापित करना चाहिए कि www.google.com पर सभी लुकअप 74.125.236.52 को हल करेंगे; यह आपके स्थानीय DNS सर्वर में या आपके ओएस की hosts फ़ाइल में किया जाना चाहिए; आपको अन्य डोमेन में भी प्रविष्टियां जोड़ने की आवश्यकता हो सकती है। कहने की जरूरत नहीं है, आपको यह सुनिश्चित करने की आवश्यकता होगी कि यह आपके आईएसपी द्वारा रिकॉर्ड किए गए रिकॉर्ड के अनुरूप है।

+0

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

+0

@WinOrWin, [इस साइट] (http://exampledepot.com/egs/javax.net.ssl/TrustAll.html) एक TrustManager का एक उदाहरण में शामिल है। हालांकि, मैं उत्पादन में उसी कोड का उपयोग करने की अनुशंसा नहीं करता, क्योंकि TrustManager सर्वर के प्रमाण पत्र को बिल्कुल सत्यापित नहीं करता है। आपको क्या करना चाहिए, यह सत्यापित करने के लिए चेक शामिल करना है कि '74.125.236.52' द्वारा प्रस्तुत सर्वर' www.google.com' को जारी किया गया है। यह निश्चित रूप से, आपके DNS लुकअप को सही करने के रूप में पसंद नहीं किया गया है; मैं सुझाव देता हूं कि वायरसहार्क डंप प्राप्त करने के लिए क्या गलत हो रहा है जिसके परिणामस्वरूप 'मेजबान' फ़ाइल को अनदेखा किया जा रहा है। –

+3

यह एक ट्रस्टमैनगर मुद्दा नहीं है। यह एक HTTPS होस्टनाम सत्यापनकर्ता समस्या है। DNS समाधान इसे हल करेगा। कोई ट्रस्टमैनेजर इसे हल नहीं कर सकता है। – EJP

25

आप here वर्णित के रूप में HostnameVerifier सेट करने का भी प्रयास कर सकते हैं। इस त्रुटि से बचने के लिए यह मेरे लिए काम किया।

// Do not do this in production!!! 
HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER; 

DefaultHttpClient client = new DefaultHttpClient(); 

SchemeRegistry registry = new SchemeRegistry(); 
SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory(); 
socketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier); 
registry.register(new Scheme("https", socketFactory, 443)); 
SingleClientConnManager mgr = new SingleClientConnManager(client.getParams(), registry); 
DefaultHttpClient httpClient = new DefaultHttpClient(mgr, client.getParams()); 

// Set verifier  
HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier); 

// Example send http request 
final String url = "https://encrypted.google.com/"; 
HttpPost httpPost = new HttpPost(url); 
HttpResponse response = httpClient.execute(httpPost); 
+3

का उपयोग करते हुए इस होस्ट नाम सत्यापनकर्ता आम तौर पर एक बुरा विचार है (देखें [इस सवाल] (http://security.stackexchange.com/q/22965/2435))। – Bruno

+0

जावा के लिए बहिष्कृत संसाधन 1.8 – nabsATX

+0

आप इसे दो बार क्यों सेट करते हैं? – pedr0

2

चिंता यह है कि हमें ALLOW_ALL_HOSTNAME_VERIFIER का उपयोग नहीं करना चाहिए।

मैं अपने स्वयं के होस्टनाम सत्यापनकर्ता को कैसे कार्यान्वित करता हूं? https://www.rideforrainbows.org/ के खिलाफ

class MyHostnameVerifier implements org.apache.http.conn.ssl.X509HostnameVerifier 
{ 
    @Override 
    public boolean verify(String host, SSLSession session) { 
     String sslHost = session.getPeerHost(); 
     System.out.println("Host=" + host); 
     System.out.println("SSL Host=" + sslHost);  
     if (host.equals(sslHost)) { 
      return true; 
     } else { 
      return false; 
     } 
    } 

    @Override 
    public void verify(String host, SSLSocket ssl) throws IOException { 
     String sslHost = ssl.getInetAddress().getHostName(); 
     System.out.println("Host=" + host); 
     System.out.println("SSL Host=" + sslHost);  
     if (host.equals(sslHost)) { 
      return; 
     } else { 
      throw new IOException("hostname in certificate didn't match: " + host + " != " + sslHost); 
     } 
    } 

    @Override 
    public void verify(String host, X509Certificate cert) throws SSLException { 
     throw new SSLException("Hostname verification 1 not implemented"); 
    } 

    @Override 
    public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException { 
     throw new SSLException("Hostname verification 2 not implemented"); 
    } 
} 

आइए परीक्षण है जो एक साझा सर्वर पर होस्ट कर रहा है।

public static void main (String[] args) throws Exception { 
    //org.apache.http.conn.ssl.SSLSocketFactory sf = org.apache.http.conn.ssl.SSLSocketFactory.getSocketFactory(); 
    //sf.setHostnameVerifier(new MyHostnameVerifier()); 
    //org.apache.http.conn.scheme.Scheme sch = new Scheme("https", 443, sf); 

    org.apache.http.client.HttpClient client = new DefaultHttpClient(); 
    //client.getConnectionManager().getSchemeRegistry().register(sch); 
    org.apache.http.client.methods.HttpPost post = new HttpPost("https://www.rideforrainbows.org/"); 
    org.apache.http.HttpResponse response = client.execute(post); 
    java.io.InputStream is = response.getEntity().getContent(); 
    java.io.BufferedReader rd = new java.io.BufferedReader(new java.io.InputStreamReader(is)); 
    String line; 
    while ((line = rd.readLine()) != null) { 
     System.out.println(line); 
    } 
} 

SSLException:

सूत्र में अपवाद "मुख्य" javax.net.ssl.SSLException: प्रमाण पत्र में होस्ट नाम से मेल नहीं खाती: www.rideforrainbows.org = stac.rt.sg या stac.rt.sg या org.apache.http.conn.ssl.AbstractVerifier.verify (AbstractVerifier.java:231) पर www.stac.rt.sg

...

MyHostnameVerifier साथ क्या :

public static void main (String[] args) throws Exception { 
    org.apache.http.conn.ssl.SSLSocketFactory sf = org.apache.http.conn.ssl.SSLSocketFactory.getSocketFactory(); 
    sf.setHostnameVerifier(new MyHostnameVerifier()); 
    org.apache.http.conn.scheme.Scheme sch = new Scheme("https", 443, sf); 

    org.apache.http.client.HttpClient client = new DefaultHttpClient(); 
    client.getConnectionManager().getSchemeRegistry().register(sch); 
    org.apache.http.client.methods.HttpPost post = new HttpPost("https://www.rideforrainbows.org/"); 
    org.apache.http.HttpResponse response = client.execute(post); 
    java.io.InputStream is = response.getEntity().getContent(); 
    java.io.BufferedReader rd = new java.io.BufferedReader(new java.io.InputStreamReader(is)); 
    String line; 
    while ((line = rd.readLine()) != null) { 
     System.out.println(line); 
    } 
} 

शो:

होस्ट = www.rideforrainbows.org
एसएसएल होस्ट = www.rideforrainbows.org

कम से कम मैं (मेजबान तुलना करने के लिए तर्क है == एसएसएल होस्ट) और सच वापसी।

उपर्युक्त स्रोत कोड httpclient-4.2.3.jar और httpclient-4.3.3.jar के लिए काम कर रहा है।

+1

आपका कार्यान्वयन केवल एक रिवर्स DNS लुकअप कर रहा है, यह प्रमाणपत्र से कुछ भी जांच नहीं रहा है। इसलिए यह असुरक्षित है। – Bruno

+0

यह मेरी समस्या हल – Jxadro

4

httpclient-4.3.3.jar में, वहाँ एक और HttpClient उपयोग करने के लिए है:

public static void main (String[] args) throws Exception { 
    // org.apache.http.client.HttpClient client = new DefaultHttpClient(); 
    org.apache.http.client.HttpClient client = HttpClientBuilder.create().build(); 
    System.out.println("HttpClient = " + client.getClass().toString()); 
    org.apache.http.client.methods.HttpPost post = new HttpPost("https://www.rideforrainbows.org/"); 
    org.apache.http.HttpResponse response = client.execute(post); 
    java.io.InputStream is = response.getEntity().getContent(); 
    java.io.BufferedReader rd = new java.io.BufferedReader(new java.io.InputStreamReader(is)); 
    String line; 
    while ((line = rd.readLine()) != null) { 
     System.out.println(line); 
    } 
} 

यह HttpClientBuilder.create() निर्माण()org.apache.http.impl वापस आ जाएगी।। क्लाइंट .InternalHttpClient। यह प्रमाणपत्र में होस्टनाम को संभाल सकता है समस्या से मेल नहीं खाता है।

+0

इस उत्तर HTTP पुस्तकालय डाउनलोड करने के लिए लिंक प्रदान करके सुधार किया जा सकता। –

+0

यह उत्तर कैसे हल करेगा? –

+0

इसके अलावा, क्या यह https://issues.apache.org/jira/browse/HTTPCLIENT-1119 से संबंधित है? –

7

httpcliet4.3.3 में एक क्लीनर दृष्टिकोण (केवल परीक्षण पर्यावरण के लिए) निम्नानुसार है।

SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext,SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); 

CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build(); 
+0

ये कक्षाएं उपलब्ध नहीं हैं –

13

मुझे भी इसी तरह की समस्या थी। मैं एंड्रॉइड के DefaultHttpClient का उपयोग कर रहा था। मैंने पढ़ा है कि HttpsURLConnection इस तरह के अपवाद को संभाल सकता है। इसलिए मैंने कस्टम होस्टनाम वेरिफायर बनाया जो HttpsURLConnection से सत्यापनकर्ता का उपयोग करता है। मैंने कार्यान्वयन को कस्टम HttpClient में भी लपेट लिया।

public class CustomHttpClient extends DefaultHttpClient { 

public CustomHttpClient() { 
    super(); 
    SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory(); 
    socketFactory.setHostnameVerifier(new CustomHostnameVerifier()); 
    Scheme scheme = (new Scheme("https", socketFactory, 443)); 
    getConnectionManager().getSchemeRegistry().register(scheme); 
} 

यहाँ CustomHostnameVerifier वर्ग है:

public class CustomHostnameVerifier implements org.apache.http.conn.ssl.X509HostnameVerifier { 

@Override 
public boolean verify(String host, SSLSession session) { 
    HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier(); 
    return hv.verify(host, session); 
} 

@Override 
public void verify(String host, SSLSocket ssl) throws IOException { 
} 

@Override 
public void verify(String host, X509Certificate cert) throws SSLException { 

} 

@Override 
public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException { 

} 

}

+0

मेरा दिन बचाया :) धन्यवाद !! –

+0

एक चीज़ जानना चाहते हैं, क्या यह एसएसएल प्रमाणपत्र पास करके/छोड़ने का एक प्रकार है? –

+1

हम अभी भी Uttl को HttpsURLConnection verifiier के माध्यम से सत्यापित कर रहे हैं, इसलिए कोई SSL बाईपासिंग नहीं है। – granko87

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