HTTPS를 통한 HttpClient를 사용하여 모든 인증서 신뢰


393

최근 HttpClientover Https ( here here ) 에 관한 질문을 게시했습니다 . 전진했지만 새로운 문제가 발생했습니다. 마지막 문제와 마찬가지로, 나에게 적합한 예제를 찾을 수없는 것 같습니다. 기본적으로 클라이언트가 인증서를 수락하기를 원하지만 (단 하나의 서버 만 가리 키기 때문에) 계속javax.net.ssl.SSLException: Not trusted server certificate exception.

그래서 이것이 내가 가진 것입니다 :


    public void connect() throws A_WHOLE_BUNCH_OF_EXCEPTIONS {

        HttpPost post = new HttpPost(new URI(PROD_URL));
        post.setEntity(new StringEntity(BODY));

        KeyStore trusted = KeyStore.getInstance("BKS");
        trusted.load(null, "".toCharArray());
        SSLSocketFactory sslf = new SSLSocketFactory(trusted);
        sslf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

        SchemeRegistry schemeRegistry = new SchemeRegistry();
        schemeRegistry.register(new Scheme ("https", sslf, 443));
        SingleClientConnManager cm = new SingleClientConnManager(post.getParams(),
                schemeRegistry);

        HttpClient client = new DefaultHttpClient(cm, post.getParams());
        HttpResponse result = client.execute(post);
    }

그리고 내가받는 오류는 다음과 같습니다.

    W/System.err(  901): javax.net.ssl.SSLException: Not trusted server certificate 
    W/System.err(  901):    at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:360) 
    W/System.err(  901):    at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:92) 
    W/System.err(  901):    at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:321) 
    W/System.err(  901):    at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:129) 
    W/System.err(  901):    at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164) 
    W/System.err(  901):    at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119) 
    W/System.err(  901):    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:348) 
    W/System.err(  901):    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555) 
    W/System.err(  901):    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487) 
    W/System.err(  901):    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465) 
    W/System.err(  901):    at me.harrisonlee.test.ssl.MainActivity.connect(MainActivity.java:129) 
    W/System.err(  901):    at me.harrisonlee.test.ssl.MainActivity.access$0(MainActivity.java:77) 
    W/System.err(  901):    at me.harrisonlee.test.ssl.MainActivity$2.run(MainActivity.java:49) 
    W/System.err(  901): Caused by: java.security.cert.CertificateException: java.security.InvalidAlgorithmParameterException: the trust anchors set is empty 
    W/System.err(  901):    at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:157) 
    W/System.err(  901):    at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:355) 
    W/System.err(  901):    ... 12 more 
    W/System.err(  901): Caused by: java.security.InvalidAlgorithmParameterException: the trust anchors set is empty 
    W/System.err(  901):    at java.security.cert.PKIXParameters.checkTrustAnchors(PKIXParameters.java:645) 
    W/System.err(  901):    at java.security.cert.PKIXParameters.<init>(PKIXParameters.java:89) 
    W/System.err(  901):    at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.<init>(TrustManagerImpl.java:89) 
    W/System.err(  901):    at org.apache.harmony.xnet.provider.jsse.TrustManagerFactoryImpl.engineGetTrustManagers(TrustManagerFactoryImpl.java:134) 
    W/System.err(  901):    at javax.net.ssl.TrustManagerFactory.getTrustManagers(TrustManagerFactory.java:226)W/System.err(  901):     at org.apache.http.conn.ssl.SSLSocketFactory.createTrustManagers(SSLSocketFactory.java:263) 
    W/System.err(  901):    at org.apache.http.conn.ssl.SSLSocketFactory.<init>(SSLSocketFactory.java:190) 
    W/System.err(  901):    at org.apache.http.conn.ssl.SSLSocketFactory.<init>(SSLSocketFactory.java:216) 
    W/System.err(  901):    at me.harrisonlee.test.ssl.MainActivity.connect(MainActivity.java:107) 
    W/System.err(  901):    ... 2 more

17
내부 용으로이 작업을 수행해야했습니다. 나는 중간 공격에서 사람에게 앱을 열어서 세션을 가로채는 누군가에게 취약하기 때문에 회사 외부 사용자가 앱을 사용하지 못하게하기를 정말로 바랍니다. 그럼에도 불구하고 실제 인증서를 손에 넣을 때까지 일부 테스트를 위해이 임시 작업을 수행해야합니다.
Dean Hiller

4.3 아파치 http 클라이언트에서 이러한 솔루션을 시도했지만 대부분 더 이상 사용되지 않습니다. 여기에 솔루션을 사용 중지되지 않습니다 stackoverflow.com/a/18941950/2039471
알렉산더 Chzhen

Java 1.6에는 이러한 시나리오에서도 문제가되는 SNI 지원이 없습니다. 요청을 올바르게 구성하지 않으면 요청과 일치하지 않는 인증서를 얻을 수 있습니다. 참조 issues.apache.org/jira/browse/HTTPCLIENT-1119
브롱 데이비스

2
이 질문은 잘못된 추론의 예로서 세계에서 가장 위험한 법 (The Most Dangerous Code)에서 인용되었습니다. (연구 논문 : cs.utexas.edu/~shmat/shmat_ccs12.pdf )
mk_

답변:


421

참고 : 완전히 신뢰할 수없는 네트워크에서 사용할 프로덕션 코드에는 이것을 구현하지 마십시오. 특히 공공 인터넷을 통한 모든 것.

당신의 질문은 내가 알고 싶은 것입니다. 몇 가지 검색을 한 후 결론은 다음과 같습니다.

HttpClient 방식에서는 org.apache.http.conn.ssl.SSLSocketFactory 자체가 아닌 org.apache.http.conn.ssl.SSLSocketFactory에서 사용자 정의 클래스를 작성해야합니다. 이 게시물에서 몇 가지 단서를 찾을 수 있습니다. 사용자 정의 SSL 처리는 Android 2.2 FroYo에서 작동이 중지되었습니다 .

예를 들면 ...

import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

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

import org.apache.http.conn.ssl.SSLSocketFactory;
public class MySSLSocketFactory extends SSLSocketFactory {
    SSLContext sslContext = SSLContext.getInstance("TLS");

    public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
        super(truststore);

        TrustManager tm = new X509TrustManager() {
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }

            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }

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

        sslContext.init(null, new TrustManager[] { tm }, null);
    }

    @Override
    public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
        return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
    }

    @Override
    public Socket createSocket() throws IOException {
        return sslContext.getSocketFactory().createSocket();
    }
}

HttpClient의 인스턴스를 만드는 동안이 클래스를 사용하십시오.

public HttpClient getNewHttpClient() {
    try {
        KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
        trustStore.load(null, null);

        MySSLSocketFactory sf = new MySSLSocketFactory(trustStore);
        sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

        HttpParams params = new BasicHttpParams();
        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
        HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);

        SchemeRegistry registry = new SchemeRegistry();
        registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        registry.register(new Scheme("https", sf, 443));

        ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);

        return new DefaultHttpClient(ccm, params);
    } catch (Exception e) {
        return new DefaultHttpClient();
    }
}

BTW, 아래 링크는 HttpURLConnection 솔루션을 찾는 사람을위한 것입니다. Https 연결 안드로이드

나는 위의 두 가지 솔루션을 froyo에서 테스트했으며 모두 내 경우에는 매력처럼 작동합니다. 마지막으로 HttpURLConnection을 사용하면 리디렉션 문제가 발생할 수 있지만 이는 주제를 벗어납니다.

참고 : 모든 인증서를 신뢰하기로 결정하기 전에 해당 사이트를 완전히 알고 있어야하며 최종 사용자에게 해를 끼치 지 않을 것입니다.

실제로, 다음의 의견에서 언급 한 해커의 모의 사이트의 영향을 포함하여 위험을 신중하게 고려해야합니다. 어떤 상황에서는 모든 인증서를 관리하기가 어려울 수 있지만 모든 인증서를 신뢰하는 암시적인 단점을 더 잘 알고있을 것입니다.


150
이 답변은 아마도 모든 인증서를 신뢰하는 것은 엄청나게 안전하지 않으며 SSL의 전체 목적을 무효화합니다.
yanokwa

22
@sweeney-귀하가 생각하는 서버와 대화하고 있다고 보장하지는 않습니다. 누군가가 DNS 서버를 망가 뜨린 경우 해커의 서버와 암호화 키를 통신 할 수 있습니다.
Richard Szalay

12
@sweeney 즉, 이제 중간자 (man-in-the-middle) 공격에 대한 책임이 있습니다. 또한 해당 코드가 사양을 충족하지 않습니다. Javadoc을 확인하십시오. getAcceptedIssuers()null을 반환 할 수 없습니다.
Lorne의 후작

25
-1 모든 인증서를 수락하는 것이 끔찍한 아이디어이기 때문입니다. 잘못된 일을하는 길을 따라 Java 개발자를 행복하게 안내하는 블로그와 자습서가 너무 많기 때문에 너무 나쁩니다.
팀 벤더

57
+1 디버깅 목적으로 만 빠른 솔루션이 필요했기 때문입니다. 다른 사람들이 언급 한 보안 문제로 인해 프로덕션에서 이것을 사용하지 않을 것이지만 이것이 바로 테스트에 필요한 것입니다. 감사합니다!
Danation 2009 년

495

기본적으로 httpclient를 사용하여 Android에서 "신뢰할 수 없음"예외를 해결하는 네 가지 가능한 솔루션이 있습니다.

  1. 모든 인증서를 신뢰하십시오. 당신이하고있는 일을 정말로 알지 못한다면 이것을하지 마십시오.
  2. 인증서 만 신뢰하는 사용자 정의 SSLSocketFactory를 작성하십시오. 연결하려는 서버를 정확히 알고있는 한 작동하지만 다른 SSL 인증서를 사용하여 새 서버에 연결해야하는 즉시 앱을 업데이트해야합니다.
  3. Android의 "마스터 목록"인증서가 포함 된 키 저장소 파일을 작성한 후 직접 저장하십시오. 해당 인증서 중 어느 것이라도 만료되면 앱에서 업데이트해야합니다. 나는 이것을 할 이유를 생각할 수 없다.
  4. 내장 인증서 KeyStore를 사용하는 사용자 정의 SSLSocketFactory를 작성하십시오. 그러나 기본값으로 확인하지 못하는 경우 대체 KeyStore로 대체됩니다.

이 답변은 솔루션 # 4를 사용합니다.

해결책은 여러 키 저장소를 승인 할 수있는 SSLSocketFactory를 사용하여 고유 한 인증서를 고유 한 키 저장소에 제공 할 수 있습니다. 이를 통해 일부 Android 기기에서 누락 될 수있는 Thawte와 같은 추가 최상위 인증서를로드 할 수 있습니다. 또한 자체 서명 된 인증서도로드 할 수 있습니다. 내장 된 기본 장치 인증서를 먼저 사용하고 필요한 경우에만 추가 인증서로 대체합니다.

먼저 KeyStore에서 누락 된 인증서를 확인해야합니다. 다음 명령을 실행하십시오.

openssl s_client -connect www.yourserver.com:443

그리고 당신은 다음과 같은 출력을 볼 수 있습니다 :

Certificate chain
 0 s:/O=www.yourserver.com/OU=Go to 
   https://www.thawte.com/repository/index.html/OU=Thawte SSL123 
   certificate/OU=Domain Validated/CN=www.yourserver.com
   i:/C=US/O=Thawte, Inc./OU=Domain Validated SSL/CN=Thawte DV SSL CA
 1 s:/C=US/O=Thawte, Inc./OU=Domain Validated SSL/CN=Thawte DV SSL CA
   i:/C=US/O=thawte, Inc./OU=Certification Services Division/OU=(c) 
   2006 thawte, Inc. - For authorized use only/CN=thawte Primary Root CA

보시다시피 루트 인증서는 Thawte의 것입니다. 공급자의 웹 사이트로 이동하여 해당 인증서를 찾으십시오. 우리에게는 여기 에 있으며, 필요한 것은 Copyright 2006이라는 것을 알 수 있습니다.

자체 서명 인증서를 사용하는 경우 서명 인증서가 이미 있으므로 이전 단계를 수행하지 않아도됩니다.

그런 다음 누락 된 서명 인증서가 포함 된 키 저장소 파일을 작성하십시오. Crazybob은 Android 에서이 작업을 수행하는 방법에 대한 세부 정보를 가지고 있지만 아이디어는 다음과 같습니다.

Bouncy Castle 제공자 라이브러리가없는 경우 http://www.bouncycastle.org/latest_releases.html 에서 다운로드 하십시오 . 이것은 아래 클래스 경로로 진행됩니다.

서버에서 인증서를 추출하고 pem 파일을 작성하는 명령을 실행하십시오. 이 경우 mycert.pem입니다.

echo | openssl s_client -connect ${MY_SERVER}:443 2>&1 | \
 sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > mycert.pem

그런 다음 다음 명령을 실행하여 키 저장소를 작성하십시오.

export CLASSPATH=/path/to/bouncycastle/bcprov-jdk15on-155.jar
CERTSTORE=res/raw/mystore.bks
if [ -a $CERTSTORE ]; then
    rm $CERTSTORE || exit 1
fi
keytool \
      -import \
      -v \
      -trustcacerts \
      -alias 0 \
      -file <(openssl x509 -in mycert.pem) \
      -keystore $CERTSTORE \
      -storetype BKS \
      -provider org.bouncycastle.jce.provider.BouncyCastleProvider \
      -providerpath /path/to/bouncycastle/bcprov-jdk15on-155.jar \
      -storepass some-password

위의 스크립트는 결과를에 배치한다는 것을 알 수 있습니다 res/raw/mystore.bks. 이제 누락 된 인증서를 제공하는 Android 앱에로드 할 파일이 있습니다.

이렇게하려면 SSL 구성표에 SSLSocketFactory를 등록하십시오.

final SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(new Scheme("https", createAdditionalCertsSSLSocketFactory(), 443));

// and then however you create your connection manager, I use ThreadSafeClientConnManager
final HttpParams params = new BasicHttpParams();
...
final ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(params,schemeRegistry);

SSLSocketFactory를 작성하려면 다음을 수행하십시오.

protected org.apache.http.conn.ssl.SSLSocketFactory createAdditionalCertsSSLSocketFactory() {
    try {
        final KeyStore ks = KeyStore.getInstance("BKS");

        // the bks file we generated above
        final InputStream in = context.getResources().openRawResource( R.raw.mystore);  
        try {
            // don't forget to put the password used above in strings.xml/mystore_password
            ks.load(in, context.getString( R.string.mystore_password ).toCharArray());
        } finally {
            in.close();
        }

        return new AdditionalKeyStoresSSLSocketFactory(ks);

    } catch( Exception e ) {
        throw new RuntimeException(e);
    }
}

마지막으로 AdditionalKeyStoresSSLSocketFactory 코드는 새 KeyStore를 승인하고 내장 KeyStore가 SSL 인증서의 유효성 검증에 실패하는지 확인합니다.

/**
 * Allows you to trust certificates from additional KeyStores in addition to
 * the default KeyStore
 */
public class AdditionalKeyStoresSSLSocketFactory extends SSLSocketFactory {
    protected SSLContext sslContext = SSLContext.getInstance("TLS");

    public AdditionalKeyStoresSSLSocketFactory(KeyStore keyStore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
        super(null, null, null, null, null, null);
        sslContext.init(null, new TrustManager[]{new AdditionalKeyStoresTrustManager(keyStore)}, null);
    }

    @Override
    public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException {
        return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
    }

    @Override
    public Socket createSocket() throws IOException {
        return sslContext.getSocketFactory().createSocket();
    }



    /**
     * Based on http://download.oracle.com/javase/1.5.0/docs/guide/security/jsse/JSSERefGuide.html#X509TrustManager
     */
    public static class AdditionalKeyStoresTrustManager implements X509TrustManager {

        protected ArrayList<X509TrustManager> x509TrustManagers = new ArrayList<X509TrustManager>();


        protected AdditionalKeyStoresTrustManager(KeyStore... additionalkeyStores) {
            final ArrayList<TrustManagerFactory> factories = new ArrayList<TrustManagerFactory>();

            try {
                // The default Trustmanager with default keystore
                final TrustManagerFactory original = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                original.init((KeyStore) null);
                factories.add(original);

                for( KeyStore keyStore : additionalkeyStores ) {
                    final TrustManagerFactory additionalCerts = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                    additionalCerts.init(keyStore);
                    factories.add(additionalCerts);
                }

            } catch (Exception e) {
                throw new RuntimeException(e);
            }



            /*
             * Iterate over the returned trustmanagers, and hold on
             * to any that are X509TrustManagers
             */
            for (TrustManagerFactory tmf : factories)
                for( TrustManager tm : tmf.getTrustManagers() )
                    if (tm instanceof X509TrustManager)
                        x509TrustManagers.add( (X509TrustManager)tm );


            if( x509TrustManagers.size()==0 )
                throw new RuntimeException("Couldn't find any X509TrustManagers");

        }

        /*
         * Delegate to the default trust manager.
         */
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            final X509TrustManager defaultX509TrustManager = x509TrustManagers.get(0);
            defaultX509TrustManager.checkClientTrusted(chain, authType);
        }

        /*
         * Loop over the trustmanagers until we find one that accepts our server
         */
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            for( X509TrustManager tm : x509TrustManagers ) {
                try {
                    tm.checkServerTrusted(chain,authType);
                    return;
                } catch( CertificateException e ) {
                    // ignore
                }
            }
            throw new CertificateException();
        }

        public X509Certificate[] getAcceptedIssuers() {
            final ArrayList<X509Certificate> list = new ArrayList<X509Certificate>();
            for( X509TrustManager tm : x509TrustManagers )
                list.addAll(Arrays.asList(tm.getAcceptedIssuers()));
            return list.toArray(new X509Certificate[list.size()]);
        }
    }

}

안녕하세요 @emmby, 이것은 내 문제에 대한 완벽한 답변 인 것 같지만 여전히 SSL 연결이 없습니다. 한번 봐주시겠습니까? http://stackoverflow.com/questions/7822381/need-help-understanding-certificate-chains
Matthias B

훌륭한 글쓰기 @emmby에 감사드립니다! 때로는 정말 긴 지연이 발생하고 javax.net.ssl.SSLException : Read error :가 발생합니다. 어떤 생각? 솔루션이 stackoverflow.com/questions/5909308/android-2-3-4-ssl-problem 과 동일한 경우 어떻게 시간 초과를 설정할 수 있습니까?
Edwin Evans

3
@emmby,이 코드를 어디에 넣어야하는지 알 수 있습니까? CLASSPATH = bcprov-jdk16-145.jar CERTSTORE = res / raw / mystore.bks if [-a $ CERTSTORE]; 그런 다음 rm $ CERTSTORE || exit 1 fi keytool \ -import \ -v \ -trustcacerts \ -alias 0 \ -file <(openssl x509 -incert.pem) \ -keystore $ CERTSTORE \ -storetype BKS \ -provider org.bouncycastle.jce.provider. BouncyCastleProvider \ -providerpath /usr/share/java/bcprov.jar \ -storepass some-password
Rikki Tikki Tavi

1
안녕하세요 @emmby. 내 앱에서 솔루션을 사용하고 내 서버의 자체 서명 된 인증서를 사용하고 있지만 checkServerTrusted () 메서드 에서 CertificateException ()가져옵니다 . 나는 그 예외를 던지려고 노력했다. 그것이 내 서버 인증서의 유효성을 검사하지 않으면 다른 방법으로 처리 할 수 ​​있습니까?이 경우 가장 좋은 해결책은 무엇입니까?
Ankit

7
정답으로 표시해야합니다. 내가 본 것 중 가장 철저하고 잘 작성된 답변 중 하나. 마약
카치

74

이 코드를 앞에 추가하면 HttpsURLConnection완료됩니다. 알았어

private void trustEveryone() { 
    try { 
            HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier(){ 
                    public boolean verify(String hostname, SSLSession session) { 
                            return true; 
                    }}); 
            SSLContext context = SSLContext.getInstance("TLS"); 
            context.init(null, new X509TrustManager[]{new X509TrustManager(){ 
                    public void checkClientTrusted(X509Certificate[] chain, 
                                    String authType) throws CertificateException {} 
                    public void checkServerTrusted(X509Certificate[] chain, 
                                    String authType) throws CertificateException {} 
                    public X509Certificate[] getAcceptedIssuers() { 
                            return new X509Certificate[0]; 
                    }}}, new SecureRandom()); 
            HttpsURLConnection.setDefaultSSLSocketFactory( 
                            context.getSocketFactory()); 
    } catch (Exception e) { // should never happen 
            e.printStackTrace(); 
    } 
} 

이것이 도움이되기를 바랍니다.


22
허용 된 답변에서 위의 설명을 참조하십시오. 이 '솔루션'은 근본적으로 안전하지 않습니다.
Lorne의 후작

5
이상적인 Q & D 솔루션입니다. 짧고 "그냥 작동합니다."
Steve Smith

5
테스트 목적으로 완벽한 답변 !!! 그리고 네, 생산에 사용하는 것은 좋지 않은 생각이지만 질문 제목을 보는 모든 사람들에게 분명해야합니다. 여전히 동일한 / 보안 수준으로 최상의 / 최단 / 응답합니다!
Levite

34

이것은 나쁜 생각입니다. 모든 인증서를 신뢰하는 것은 SSL을 전혀 사용하지 않는 것보다 약간 좋습니다. "내 서버가 하나의 서버 만 가리 키기 때문에 클라이언트가 모든 인증서를 수락하기를 원합니다"라고 말하면 이것은 "하나의 서버"를 가리키는 것이 안전하며 공용 네트워크에 있지 않다는 것을 의미합니다.

인증서를 신뢰하면 중간자 공격에 완전히 개방됩니다. 사용자와 최종 서버와 별도의 SSL 연결을 설정하여 누구나 연결을 프록시 할 수 있습니다. 그런 다음 MITM은 전체 요청 및 응답에 액세스 할 수 있습니다. 처음에 실제로 SSL이 필요하지 않은 경우 (메시지에 민감한 것은 없으며 인증을 수행하지 않음) 모든 인증서를 맹목적으로 신뢰해서는 안됩니다.

keytool을 사용하여 공개 인증서를 jks에 추가하고 소켓 팩토리를 빌드하는 데 다음과 같이 사용하십시오.

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

    // get user password and file input stream
    char[] password = ("mykspassword")).toCharArray();
    ClassLoader cl = this.getClass().getClassLoader();
    InputStream stream = cl.getResourceAsStream("myjks.jks");
    ks.load(stream, password);
    stream.close();

    SSLContext sc = SSLContext.getInstance("TLS");
    KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
    TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");

    kmf.init(ks, password);
    tmf.init(ks);

    sc.init(kmf.getKeyManagers(), tmf.getTrustManagers(),null);

    return sc.getSocketFactory();

여기에는주의해야 할 사항이 하나 있습니다. 인증서는 결국 만료되고 코드는 그때 작동을 멈 춥니 다. 인증서를 보면 언제 이런 일이 일어날 지 쉽게 결정할 수 있습니다.


5
당신이 클라이언트 인증서 인증을 사용하지 않는 경우, 클라이언트 측에서, 당신은의 KeyManager (사용하지 않아도 null에서 SSLContext.init). You should also use the default algorithms (KMF/TMF.getDefaultAlgorithm() ), instead of hard-coding SunX509` (자세한 그래서 TMF의 기본이 실제로 때문이다 PKIX. 썬 / 오라클 JVM에)
브루노

루트 인증서 파일을 사용할 준비가 되셨습니까? (브라우저처럼)
dani herrera

어디 myjks.jks에서 왔습니까?
zionpi

1
@zionpi Java "keytool"을 사용하여 생성됩니다.
Dan

22

API 8부터이 방법으로 테스트 목적으로 HttpURLConnection SSL 검사를 비활성화 할 수 있습니다.

    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    if (conn instanceof HttpsURLConnection) {
        HttpsURLConnection httpsConn = (HttpsURLConnection) conn;
        httpsConn.setSSLSocketFactory(SSLCertificateSocketFactory.getInsecure(0, null));
        httpsConn.setHostnameVerifier(new AllowAllHostnameVerifier());
    }

2
org.apache.http.conn.ssl.AllowAllHostnameVerifier더 이상 사용되지 않습니다.
zackygaurav

2
@zackygaurav는에 따르면 javadoc에 , AllowAllHostnameVerifier로 대체 NoopHostnameVerifier"
DLight

10

HttpComponents의 API가 변경되었습니다. 아래 코드와 함께 작동합니다.

public static HttpClient getTestHttpClient() {
    try {
        SSLSocketFactory sf = new SSLSocketFactory(new TrustStrategy(){
            @Override
            public boolean isTrusted(X509Certificate[] chain,
                    String authType) throws CertificateException {
                return true;
            }
        }, new AllowAllHostnameVerifier());

        SchemeRegistry registry = new SchemeRegistry();
        registry.register(new Scheme("https",8444, sf));
        ClientConnectionManager ccm = new ThreadSafeClientConnManager(registry);
        return new DefaultHttpClient(ccm);
    } catch (Exception e) {
        e.printStackTrace();
        return new DefaultHttpClient();
    }
}

맞춤형 신뢰 전략을 사용하는 것이 정답입니다. 감사.
매트 프리드먼

10

https://stackoverflow.com/a/6378872/1553004의 위 코드 는 호스트 이름 검증자를 호출해야한다는 점을 제외하고는 정확합니다.

    @Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException {
    SSLSocket sslSocket = (SSLSocket)sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
    getHostnameVerifier().verify(host, sslSocket);
    return sslSocket;
}

이 수정 프로그램을 추가하기 위해 명시 적으로 stackoverflow에 가입했습니다. 내 경고에 유의하십시오!


첫 번째 연결에서이 방법으로 인증서를 확인하면 후속 연결로 무엇을합니까? 첫 번째 연결에서 얻은 지식을 활용하십니까? 연결 시도 3에서 동일한 이름의 가짜 인증서가 사용되면 어떻게됩니까?
jww

6

httpclient-4.5를 사용하는 사람들에 대한 응답을 추가하고 있으며 4.4에서도 작동합니다.

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.fluent.ContentResponseHandler;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;



public class HttpClientUtils{

public static HttpClient getHttpClientWithoutSslValidation_UsingHttpClient_4_5_2() {
    try {
        SSLContextBuilder builder = new SSLContextBuilder();
        builder.loadTrustMaterial(null, new TrustStrategy() {
            @Override
            public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                return true;
            }
        });
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build(), new NoopHostnameVerifier());
        CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build(); 
        return httpclient;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
}

새로운 NoopHostnameVerifier () 클래스 란 무엇입니까?
Mushtakim Ahmed Ansari

1
@MushtakimAhmedAnsari 문서에서 : "NO_OP HostnameVerifier는 기본적으로 호스트 이름 확인을 해제합니다.이 구현은 작동하지 않으며 SSLException을 발생시키지 않습니다."
raisercostin

큰 답변을 주셔서 감사합니다.이 투표는 더 많은 표를 얻어야합니다.
Abhay Dwivedi

어떻게 사용합니까? 또는 단순히 클래스를 사용하면 SSL 인증서 확인을 무시할 것을 제안합니까?
behelit

예. 이 세션 객체를 사용하면하지 않습니다 검증 HTTPS 인증서
raisercostin

4

모든 인증서를 신뢰하는 것은 나에게 실질적인 대안이 아니므로 HttpsURLConnection이 새 인증서를 신뢰하도록하기 위해 다음을 수행했습니다 ( http://nelenkov.blogspot.jp/2011/12/using-custom-certificate-trust-store- 참조). on.html ).

  1. 인증서를 받으십시오. Firefox에서 인증서를 내 보내면 (작은 자물쇠 아이콘 클릭, 인증서 세부 정보 가져 오기, 내보내기 클릭)이 작업을 완료 한 다음 portecle 을 사용하여 신뢰 저장소 (BKS)를 내보냈 습니다.

  2. 다음 코드를 사용하여 /res/raw/geotrust_cert.bks에서 Truststore를로드하십시오.

        final KeyStore trustStore = KeyStore.getInstance("BKS");
        final InputStream in = context.getResources().openRawResource(
                R.raw.geotrust_cert);
        trustStore.load(in, null);
    
        final TrustManagerFactory tmf = TrustManagerFactory
                .getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(trustStore);
    
        final SSLContext sslCtx = SSLContext.getInstance("TLS");
        sslCtx.init(null, tmf.getTrustManagers(),
                new java.security.SecureRandom());
    
        HttpsURLConnection.setDefaultSSLSocketFactory(sslCtx
                .getSocketFactory());

이 오류가 발생합니다. IOExceptionjavax.net.ssl.SSLPeerUnverifiedException: No peer certificate. 이것은 위의 설정이 완료된 후 HttpClient에서 실제 실행 호출을 수행 할 때입니다.
Michael

3

다음은 4.1.2 httpclient 코드를 사용하는 훨씬 간단한 버전입니다. 그런 다음 적합한 트러스트 알고리즘으로 수정할 수 있습니다.

public static HttpClient getTestHttpClient() {
    try {
        SSLSocketFactory sf = new SSLSocketFactory(new TrustStrategy(){
            @Override
            public boolean isTrusted(X509Certificate[] chain,
                    String authType) throws CertificateException {
                return true;
            }
        });
        SchemeRegistry registry = new SchemeRegistry();
        registry.register(new Scheme("https", 443, sf));
        ClientConnectionManager ccm = new ThreadSafeClientConnManager(registry);
        return new DefaultHttpClient(ccm);
    } catch (Exception e) {
        return new DefaultHttpClient();
    }
}

3

"emmby"(6 월 16 일 11시 21:29에 답변 됨), 항목 # 4 : "내장 인증서 KeyStore를 사용하는 사용자 정의 SSLSocketFactory를 작성하지만 실패한 항목에 대해서는 대체 KeyStore로 대체됩니다. "기본값으로 확인하십시오."

이것은 단순화 된 구현입니다. 시스템 키 저장소를로드하고 응용 프로그램 키 저장소와 병합하십시오.

public HttpClient getNewHttpClient() {
    try {
        InputStream in = null;
        // Load default system keystore
        KeyStore trusted = KeyStore.getInstance(KeyStore.getDefaultType()); 
        try {
            in = new BufferedInputStream(new FileInputStream(System.getProperty("javax.net.ssl.trustStore"))); // Normally: "/system/etc/security/cacerts.bks"
            trusted.load(in, null); // no password is "changeit"
        } finally {
            if (in != null) {
                in.close();
                in = null;
            }
        }

        // Load application keystore & merge with system
        try {
            KeyStore appTrusted = KeyStore.getInstance("BKS"); 
            in = context.getResources().openRawResource(R.raw.mykeystore);
            appTrusted.load(in, null); // no password is "changeit"
            for (Enumeration<String> e = appTrusted.aliases(); e.hasMoreElements();) {
                final String alias = e.nextElement();
                final KeyStore.Entry entry = appTrusted.getEntry(alias, null);
                trusted.setEntry(System.currentTimeMillis() + ":" + alias, entry, null);
            }
        } finally {
            if (in != null) {
                in.close();
                in = null;
            }
        }

        HttpParams params = new BasicHttpParams();
        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
        HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);

        SSLSocketFactory sf = new SSLSocketFactory(trusted);
        sf.setHostnameVerifier(SSLSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);

        SchemeRegistry registry = new SchemeRegistry();
        registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        registry.register(new Scheme("https", sf, 443));

        ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);

        return new DefaultHttpClient(ccm, params);
    } catch (Exception e) {
        return new DefaultHttpClient();
    }
}

JKS에서 BKS로 변환하는 간단한 모드 :

keytool -importkeystore -destkeystore cacerts.bks -deststoretype BKS -providerclass org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath bcprov-jdk16-141.jar -deststorepass changeit -srcstorepass changeit -srckeystore $JAVA_HOME/jre/lib/security/cacerts -srcstoretype JKS -noprompt

* 참고 : Android 4.0 (ICS)에서 신뢰 저장소가 변경되었습니다. 추가 정보 : http://nelenkov.blogspot.com.es/2011/12/ics-trust-store-implementation.html


3

OAuth를 통해 모든 인증서가 (테스트 목적으로) 작동하도록하려면 다음 단계를 수행하십시오.

1) https://github.com/kaeppler/signpost 에서 Android OAuth API의 소스 코드를 다운로드하십시오.

2) "CommonsHttpOAuthProvider"클래스를 찾으십시오

3) 아래와 같이 변경하십시오.

public class CommonsHttpOAuthProvider extends AbstractOAuthProvider {

private static final long serialVersionUID = 1L;

private transient HttpClient httpClient;

public CommonsHttpOAuthProvider(String requestTokenEndpointUrl, String accessTokenEndpointUrl,
        String authorizationWebsiteUrl) {
    super(requestTokenEndpointUrl, accessTokenEndpointUrl, authorizationWebsiteUrl);


    //this.httpClient = new DefaultHttpClient();//Version implemented and that throws the famous "javax.net.ssl.SSLException: Not trusted server certificate" if the certificate is not signed with a CA
    this.httpClient = MySSLSocketFactory.getNewHttpClient();//This will work with all certificates (for testing purposes only)
}

위의 "MySSLSocketFactory"는 허용 된 답변을 기반으로합니다. 더 쉽게하기 위해 여기에 전체 수업이 있습니다.

package com.netcomps.oauth_example;

import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

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

import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;

//http://stackoverflow.com/questions/2642777/trusting-all-certificates-using-httpclient-over-https
public class MySSLSocketFactory extends SSLSocketFactory {

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

public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {

    super(truststore);
    TrustManager tm = new X509TrustManager() {

        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }

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

    sslContext.init(null, new TrustManager[] { tm }, null);
}

@Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
    return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
}

@Override
public Socket createSocket() throws IOException {
    return sslContext.getSocketFactory().createSocket();
}



public static HttpClient getNewHttpClient() {

    try {
        KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
        trustStore.load(null, null);

        SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
        sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

        HttpParams params = new BasicHttpParams();
        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
        HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);

        SchemeRegistry registry = new SchemeRegistry();
        registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        registry.register(new Scheme("https", sf, 443));

        ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);

        return new DefaultHttpClient(ccm, params);

    } catch (Exception e) {
        return new DefaultHttpClient();
    }
}

}

이것이 누군가를 돕기를 바랍니다.


1
문제는 HttpClientHTTPS 였다 . GitHub 프로젝트에서 Android 용 OAuth가 아닙니다.
jww

3

나는 이것을 사용했고 그것은 모든 OS에서 나를 위해 일한다.

/**
 * Disables the SSL certificate checking for new instances of {@link HttpsURLConnection} This has been created to
 * aid testing on a local box, not for use on production.
 */


private static void disableSSLCertificateChecking() {
    TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }

        @Override
        public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
            // Not implemented
        }

        @Override
        public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
            // Not implemented
        }
    } };

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

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

        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    } catch (KeyManagementException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
}

안녕하세요 @ yegor256,이 코드를 사용하고 있지만 여전히 SSL 핸드 셰이크 문제가 발생합니다
user2028


0

모든 몸은 여전히 안드로이드 2.1 방문 StartCom SSL 인증서로 어려움을 겪고 https://www.startssl.com/certs/ 과 지금의 ca.pem를 다운로드 대답 에 의해 제공 @emmby 교체

`export CLASSPATH=bcprov-jdk16-145.jar
 CERTSTORE=res/raw/mystore.bks
      if [ -a $CERTSTORE ]; then
          rm $CERTSTORE || exit 1
      fi
 keytool \
  -import \
  -v \
  -trustcacerts \
  -alias 0 \
  -file <(openssl x509 -in mycert.pem) \
  -keystore $CERTSTORE \
  -storetype BKS \
  -provider org.bouncycastle.jce.provider.BouncyCastleProvider \
  -providerpath /usr/share/java/bcprov.jar \
  -storepass some-password`

 `export CLASSPATH=bcprov-jdk16-145.jar
 CERTSTORE=res/raw/mystore.bks
      if [ -a $CERTSTORE ]; then
          rm $CERTSTORE || exit 1
      fi
 keytool \
  -import \
  -v \
  -trustcacerts \
  -alias 0 \
  -file <(openssl x509 -in ca.pem) \
  -keystore $CERTSTORE \
  -storetype BKS \
  -provider org.bouncycastle.jce.provider.BouncyCastleProvider \
  -providerpath /usr/share/java/bcprov.jar \
  -storepass some-password`

상자 밖으로 작동해야합니다. @emmby 의 완벽한 답변 후에도 하루 이상 어려움을 겪고 있었습니다 .


0

이 수업을 사용하십시오

public class WCFs
{
    //  https://192.168.30.8/myservice.svc?wsdl
private static final String NAMESPACE = "http://tempuri.org/";
private static final String URL = "192.168.30.8";
private static final String SERVICE = "/myservice.svc?wsdl";
private static String SOAP_ACTION = "http://tempuri.org/iWCFserviceMe/";


public static Thread myMethod(Runnable rp)
{
    String METHOD_NAME = "myMethod";

    SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);

    request.addProperty("Message", "Https WCF Running...");
    return _call(rp,METHOD_NAME, request);
}

protected static HandlerThread _call(final RunProcess rp,final String METHOD_NAME, SoapObject soapReq)
{
    final SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
    int TimeOut = 5*1000;

    envelope.dotNet = true;
    envelope.bodyOut = soapReq;
    envelope.setOutputSoapObject(soapReq);

    final HttpsTransportSE httpTransport_net = new HttpsTransportSE(URL, 443, SERVICE, TimeOut);

    try
    {
        HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() // use this section if crt file is handmake
        {
            @Override
            public boolean verify(String hostname, SSLSession session)
            {
                return true;
            }
        });

        KeyStore k = getFromRaw(R.raw.key, "PKCS12", "password");
        ((HttpsServiceConnectionSE) httpTransport_net.getServiceConnection()).setSSLSocketFactory(getSSLSocketFactory(k, "SSL"));


    }
    catch(Exception e){}

    HandlerThread thread = new HandlerThread("wcfTd"+ Generator.getRandomNumber())
    {
        @Override
        public void run()
        {
            Handler h = new Handler(Looper.getMainLooper());
            Object response = null;

            for(int i=0; i<4; i++)
            {
                response = send(envelope, httpTransport_net , METHOD_NAME, null);

                try
                {if(Thread.currentThread().isInterrupted()) return;}catch(Exception e){}

                if(response != null)
                    break;

                ThreadHelper.threadSleep(250);
            }

            if(response != null)
            {
                if(rp != null)
                {
                    rp.setArguments(response.toString());
                    h.post(rp);
                }
            }
            else
            {
                if(Thread.currentThread().isInterrupted())
                    return;

                if(rp != null)
                {
                    rp.setExceptionState(true);
                    h.post(rp);
                }
            }

            ThreadHelper.stopThread(this);
        }
    };

    thread.start();

    return thread;
}


private static Object send(SoapSerializationEnvelope envelope, HttpTransportSE androidHttpTransport, String METHOD_NAME, List<HeaderProperty> headerList)
{
    try
    {
        if(headerList != null)
            androidHttpTransport.call(SOAP_ACTION + METHOD_NAME, envelope, headerList);
        else
            androidHttpTransport.call(SOAP_ACTION + METHOD_NAME, envelope);

        Object res = envelope.getResponse();

        if(res instanceof SoapPrimitive)
            return (SoapPrimitive) envelope.getResponse();
        else if(res instanceof SoapObject)
            return ((SoapObject) envelope.getResponse());
    }
    catch(Exception e)
    {}

    return null;
}

public static KeyStore getFromRaw(@RawRes int id, String algorithm, String filePassword)
{
    try
    {
        InputStream inputStream = ResourceMaster.openRaw(id);
        KeyStore keystore = KeyStore.getInstance(algorithm);
        keystore.load(inputStream, filePassword.toCharArray());
        inputStream.close();

        return keystore;
    }
    catch(Exception e)
    {}

    return null;
}

public static SSLSocketFactory getSSLSocketFactory(KeyStore trustKey, String SSLAlgorithm)
{
    try
    {
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(trustKey);

        SSLContext context = SSLContext.getInstance(SSLAlgorithm);//"SSL" "TLS"
        context.init(null, tmf.getTrustManagers(), null);

        return context.getSocketFactory();
    }
    catch(Exception e){}

    return null;
}

}


0

여기에 이미지 설명을 입력하십시오

xamarin android에서 sspi가 실패했습니다.

이 솔루션을 찾았습니다. HTTPS 링크를 누르기 전에이 코드를 넣으십시오

const SslProtocols _Tls12 = (SslProtocols)0x00000C00;
const SecurityProtocolType Tls12 = (SecurityProtocolType)_Tls12;
ServicePointManager.SecurityProtocol = Tls12;

-3

모든 https와 함께 작동

httpClient = new DefaultHttpClient();

SSLContext ctx = SSLContext.getInstance("TLS");
X509TrustManager tm = new X509TrustManager() {
    public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException { }

    public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException { }

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

ctx.init(null, new TrustManager[]{tm}, null);
SSLSocketFactory ssf = new SSLSocketFactory(ctx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

httpClient.getConnectionManager().getSchemeRegistry().register(new Scheme("https", 443, ssf));

2
이 글에서 이미 논의하고 기각 한 것과 같은 안전하지 않은 비 해결 솔루션을 반복합니다.
Lorne의 후작

-3

위의 많은 답변이 있지만 제한된 시간 동안 올바르게 작동하지 못했기 때문에 같은 상황에있는 다른 사람을 위해 내 Java 테스트 목적으로 완벽하게 작동하는 아래 코드를 시도 할 수 있습니다.

    public static HttpClient wrapClient(HttpClient base) {
    try {
        SSLContext ctx = SSLContext.getInstance("TLS");
        X509TrustManager tm = new X509TrustManager() {
            public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException { }

            public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException { }

            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };
        ctx.init(null, new TrustManager[]{tm}, null);
        SSLSocketFactory ssf = new SSLSocketFactory(ctx);
        ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
        ClientConnectionManager ccm = base.getConnectionManager();
        SchemeRegistry sr = ccm.getSchemeRegistry();
        sr.register(new Scheme("https", ssf, 443));
        return new DefaultHttpClient(ccm, base.getParams());
    } catch (Exception ex) {
        return null;
    }
}

다음과 같이 전화하십시오.

DefaultHttpClient baseClient = new DefaultHttpClient();
HttpClient httpClient = wrapClient(baseClient );

참조 : http://tech.chitgoks.com/2011/04/24/how-to-avoid-javax-net-ssl-sslpeerunverifiedexception-peer-not-authenticated-problem-using-apache-httpclient/


EJP를 인용하자면 : "이 스레드에서 이미 논의되고 기각 된 동일한 악의적 인 비 해결 솔루션을 반복해야합니다 . "
jww

-4

간단히 이것을 사용하십시오-

public DefaultHttpClient wrapClient(HttpClient base) {
    try {
        SSLContext ctx = SSLContext.getInstance("TLS");
        X509TrustManager tm = new X509TrustManager() {
        public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException { }

        public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException { }

        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }
    };
    ctx.init(null, new TrustManager[]{tm}, null);
    SSLSocketFactory ssf = new SSLSocketFactory(ctx);
    ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    ClientConnectionManager ccm = base.getConnectionManager();
    SchemeRegistry sr = ccm.getSchemeRegistry();
    sr.register(new Scheme("https", ssf, 443));
    return new DefaultHttpClient(ccm, base.getParams());
} catch (Exception ex) {
    return null;
}
}

EJP를 인용하자면 : "이 스레드에서 이미 논의되고 기각 된 동일한 악의적 인 비 해결 솔루션을 반복해야합니다 . "
jww

-5

Daniel의 대답 은이 코드를 변경해야한다는 것을 제외하고는 좋았습니다 ...

    SchemeRegistry registry = new SchemeRegistry();
    registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
    registry.register(new Scheme("https", sf, 443));

    ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);

이 코드에 ...

    ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
    SchemeRegistry registry = ccm.getShemeRegistry()
    registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
    registry.register(new Scheme("https", sf, 443));

작동하도록


5
어떻게 작동해야합니까? 레지스트리를 작성하기 전에 참조하십시오!
Matthias B
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.