2012-01-12 4 views
8

자체 서명 된 인증서로 서버에 연결하려고합니다. 이 코드를 사용하여 모든 인증서를 수락합니다.인증서의 호스트 이름이 일치하지 않습니다?

public class CertificateAcceptor { 

    public void initializeTrustManager() { 
     try { 
      SSLContext context = SSLContext.getInstance("SSL"); 
      context.init(null, createTrustManager(), new SecureRandom()); 
      HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory()); 

     } catch (NoSuchAlgorithmException e) { 
      e.printStackTrace(); 
     } catch (KeyManagementException e) { 
      e.printStackTrace(); 
     } 
    } 

    private TrustManager[] createTrustManager() { 

    TrustManager[] trustAllCerts = new TrustManager[] { 
      new X509TrustManager() { 

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

       @Override 
       public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { 
        // leave blank to trust all clients 
       } 

       @Override 
       public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { 
        // leave blank to trust all servers 
        for (X509Certificate c : chain) { 
         System.out.println(c.toString()); 
        } 
       } 

      } 
     }; 
     return trustAllCerts; 
    } 

} 

그러나 그럼에도 불구하고 나는 다음과 같은 오류 얻을 :

javax.net.ssl.SSLException: hostname in certificate didn't match: <xyz.ch> != <localhost> 
    at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:220) 
    at org.apache.http.conn.ssl.BrowserCompatHostnameVerifier.verify(BrowserCompatHostnameVerifier.java:54) 
    at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:149) 
    at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:130) 
    at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:339) 
    at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:123) 
    at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:147) 
    at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:108) 
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:415) 
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:641) 
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:576) 

내 인증 코드가 실행되어 있는지 확인 해요, 그래서 무슨 문제가 될 수 있을까?

+1

문제는 trustmanager와 관련이 없습니다. 호스트 이름 확인은 히트하려는 서버의 인증서에 정의 된 이름 (서버의 도메인 일명 호스트 이름이어야 함)에 대해 요청한 URL의 도메인을 확인하는 별도의 보안 단계입니다. 귀하의 경우, 사용중인 URL의 이름과 서버 인증서의 이름이 일치하지 않습니다. –

답변

7

당신은, Prashant에 의해 응답이 작동하지 않을 수 있습니다 SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER

SSLSocketFactory sf = new SSLSocketFactory(
    SSLContext.getInstance("TLS"), 
    SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); 
Scheme sch = new Scheme("https", 443, sf); 
httpclient.getConnectionManager().getSchemeRegistry().register(sch); 

HttpGet httpget = new HttpGet("https://host/"); 
... 
... 
+6

이것은 잘못된 답변입니다. 당신은'ext' 확장자를 가진 키 도구를 사용하여 올바른 이름을 가진 인증서를 설정해야합니다 : ''' 키 도구 -genkeypair \ -keystore keystore.jks -dname "CN = OLEKSIYS-W3T, OU = 일 \ 자바 시스템 애플리케이션 서버, O = 썬 마이크로 시스템즈, L = 산타 클라라, ST = 캘리포니아, C = US "\ -keypass changeit를 \ -storepass changeit를 \ -keyalg RSA \ -keysize 2048 \ -alias의 s1as \ -ext SAN = DNS : localhost, IP : 127.0.0.1 \ - 유효성 9999 ''' 및 http://tersesystems.com/2014/03/23/fixing-hostname-verification/ –

+1

을 참조하십시오. 확실히이 workse, 그러나 @WillSarge nt가 맞습니다. "모두 허용"접근법을 사용하면 앱이 취약 해집니다. 지나치게 인기가있는 것은 아니지만 업무/프리랜서 프로젝트에 있어서는주의를 기울여야합니다. – Jacksonkr

+2

@Jackson 그것은 그것보다 나쁘다. FTC는 이러한 방식으로 보안을 해제 한 사람들을 고소했습니다. http://www.ftc.gov/news-events/press-releases/2014/03/fandango-credit-karma-settle-ftc-charges-they-deceived-consumers –

1

를 사용할 수 있습니다.

내가 좋아하는 그에게 무언가를 할 것,

SSLSocketFactory sf=null ; 
     SSLContext sslContext = null; 
     StringWriter writer; 
     try { 
      sslContext = SSLContext.getInstance("TLS") ; 
      sslContext.init(null,null,null); 
     } catch (NoSuchAlgorithmException e) { 
      //<YourErrorHandling> 
     } catch (KeyManagementException e){ 
      //<YourErrorHandling> 
     } 

     try{ 
      sf = new SSLSocketFactory(sslContext, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); 

     } catch(Exception e) { 
      //<YourErrorHandling> 

    } 
     Scheme scheme = new Scheme("https",443,sf); 
     httpClient.getConnectionManager().getSchemeRegistry().register(scheme); 
15

ALLOW_ALL는 정답이 아니다. 당신은 ext 확장자 키 도구를 사용하여 올바른 이름을 가진 인증서를 설정해야합니다 :

keytool -genkeypair \ 
    -keystore keystore.jks \ 
    -dname "CN=OLEKSIYS-W3T, OU=Sun Java System Application Server, O=Sun Microsystems, L=Santa Clara, ST=California, C=US" \ 
    -keypass changeit \ 
    -storepass changeit \ 
    -keyalg RSA \ 
    -keysize 2048 \ 
    -alias default \ 
    -ext SAN=DNS:localhost,IP:127.0.0.1 \ 
    -validity 9999 

은 자세한 내용은 http://tersesystems.com/2014/03/23/fixing-hostname-verification/를 참조하십시오.

+0

키 저장소를 생성 한 후에는 별도로 또는 SSLContext의 일부로 초기화합니까? 내 [전체 질문]을 볼 시간이 있다면 (http://stackoverflow.com/questions/30105561/find-or-intialize-the-keystore-needed-to-solve-hostname-in-certificate-didnt-m) 감사 드리고 싶군요. –

+0

인증서를 트러스트 스토어에 추가해야합니다. 이를 수행하는 일반적인 방법은 keytool을 사용하여 cacerts에 추가하거나 다른 트러스트 스토어를 가리 키도록 시스템 등록 정보 javax.net.ssl.trustStore를 설정하는 것입니다. –

0

Java SE 6 이하는 SNI를 지원하지 않습니다. 즉, 하나의 IP는 하나의 SSL 인증서 만 가질 수 있습니다. 하지만 내 서버에는 다른 SSL 인증서가있는 3 개의 다른 api가있었습니다. Java SE 7 이상은 SNI를 지원하며 모든 것이 잘 작동했습니다. (또는 서버에서 하나의 API 만 실행)

관련 문제