[java] javax.net.ssl.SSLHandshakeException 오류를 해결하는 방법?

제품 목록을 얻기 위해 인벤토리 API를 설정하기 위해 VPN에 연결했는데 제대로 작동합니다. 일단 웹 서비스에서 결과를 얻고 UI에 바인딩합니다. 또한 PayPal을 내 응용 프로그램과 통합하여 결제 전화를 걸 때 Express Checkout을 수행하면이 오류가 발생합니다. 백엔드 프로세스에 서블릿을 사용합니다. 누구든지이 문제를 해결하는 방법을 말할 수 있습니까?

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: 
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path to requested target



답변

먼저 연결하려는 서버에서 공개 인증서를 얻어야합니다. 서버 관리자에게 연락하여 요청 하거나 OpenSSL을 사용하여 다운로드 하거나 HTTP 서버 인 것처럼 보이므로 브라우저에 연결하여 페이지의 보안 정보를 보는 등 다양한 방법으로 수행 할 수 있습니다. , 인증서 사본 저장. (Google은 특정 브라우저에서 수행 할 작업을 정확히 알려줄 수 있습니다.)

이제 인증서를 파일에 저장 했으므로 JVM의 신뢰 저장소에 추가해야합니다. 에서 $JAVA_HOME/jre/lib/security/의 JRE 또는 $JAVA_HOME/lib/securityJDK를위한라는 파일 거기에 cacerts자바와 함께 제공 잘 알려진있는 인증 기관의 공개 인증서를 포함. 새 인증서를 가져 오려면 cacerts에 쓰기 권한이있는 사용자로 keytool을 실행합니다.

keytool -import -file <the cert file> -alias <some meaningful name> -keystore <path to cacerts file>

대부분 암호를 묻습니다. Java와 함께 제공되는 기본 암호는 changeit입니다. 거의 아무도 그것을 바꾸지 않습니다. 이 비교적 간단한 단계를 완료 한 후에는 안전하게 통신하고 올바른 서버 및 올바른 서버와 만 통신하고 있다는 확신을 갖게됩니다 (개인 키를 잃지 않는 한).


답변

이제이 문제를 이렇게 해결했습니다.

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.OutputStream; 

// Create a trust manager that does not validate certificate chains like the default 

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

            public java.security.cert.X509Certificate[] getAcceptedIssuers()
            {
                return null;
            }
            public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType)
            {
                //No need to implement.
            }
            public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType)
            {
                //No need to implement.
            }
        }
};

// Install the all-trusting trust manager
try 
{
    SSLContext sc = SSLContext.getInstance("SSL");
    sc.init(null, trustAllCerts, new java.security.SecureRandom());
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} 
catch (Exception e) 
{
    System.out.println(e);
}

물론이 솔루션은 keytool임시 인증서로 로컬 테스트를 사용하여 필요한 인증서를 설치할 수없는 시나리오에서만 사용해야합니다 .


답변

URL에 연결하려고 할 때마다

다른 사이트의 서버가 https 프로토콜에서 실행 중이고 인증서에 제공된 정보를 통해 통신해야한다고 요구하는 경우 다음 옵션이 있습니다.

1) 인증서를 요청 (인증서 다운로드)하고이 인증서를 신뢰 저장소로 가져옵니다. 기본 trustore java 사용은 \ Java \ jdk1.6.0_29 \ jre \ lib \ security \ cacerts에서 찾을 수 있으며 URL 연결에 다시 연결을 시도하면 수락됩니다.

2) 일반적인 비즈니스 사례에서 우리는 조직의 내부 URL에 연결할 수 있으며 이것이 정확하다는 것을 알고 있습니다. 이러한 경우 올바른 URL이라고 신뢰합니다. 위의 경우 특정 URL에 연결하기 위해 인증서를 저장하도록 요구하지 않는 코드를 사용할 수 있습니다.

2 번 포인트에 대해서는 아래 단계를 따라야합니다.

1) 모든 경우에 true를 반환하는 HttpsURLConnection에 대해 HostnameVerifier를 설정하는 메소드를 작성하여 trustStore를 신뢰하고 있음을 의미합니다.

  // trusting all certificate 
 public void doTrustToCertificates() throws Exception {
        Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
        TrustManager[] trustAllCerts = new TrustManager[]{
                new X509TrustManager() {
                    public X509Certificate[] getAcceptedIssuers() {
                        return null;
                    }

                    public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException {
                        return;
                    }

                    public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException {
                        return;
                    }
                }
        };

        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, new SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        HostnameVerifier hv = new HostnameVerifier() {
            public boolean verify(String urlHostName, SSLSession session) {
                if (!urlHostName.equalsIgnoreCase(session.getPeerHost())) {
                    System.out.println("Warning: URL host '" + urlHostName + "' is different to SSLSession host '" + session.getPeerHost() + "'.");
                }
                return true;
            }
        };
        HttpsURLConnection.setDefaultHostnameVerifier(hv);
    }

2) URL에 연결을 시도하기 전에 doTrustToCertificates를 호출하는 아래 메소드를 작성하십시오.

    // connecting to URL
    public void connectToUrl(){
     doTrustToCertificates();//  
     URL url = new URL("https://www.example.com");
     HttpURLConnection conn = (HttpURLConnection)url.openConnection(); 
     System.out.println("ResponseCode ="+conn.getResponseCode());
   }

이 호출은 응답 코드 = 200을 반환합니다. 연결이 성공했음을 의미합니다.

자세한 내용과 샘플 예는 URL을 참조하십시오 .


답변

SSLHandshakeException은 두 가지 방법으로 해결 될 수 있습니다.

  1. SSL 통합

    • SSL 가져 오기 (소스 시스템 관리자에게 요청하여 openssl 명령으로 다운로드하거나 모든 브라우저에서 인증서 다운로드)

    • JRE / lib / security에있는 신뢰 저장소 (cacerts)에 인증서를 추가하십시오.

    • vm 인수에 신뢰 저장소 위치를 “-Djavax.net.ssl.trustStore =”로 제공하십시오.

  2. SSL 무시

    이 # 2에 대해서는 다른 stackoverflow 웹 사이트의 다른 답변을 방문하십시오.
    SSL 확인을 수행하는 방법 Java로 SSL 인증서 오류를 무시 하는 방법


답변

SSL을 사용하여 연결을 시도하고 있지만 verisign과 같은 루트 인증 기관에서 확인하지 않은 인증서를 제공하는 것이 있다고 생각합니다. 기본적으로 보안 연결은 연결하려는 사람이 알고있는 경우에만 설정할 수 있습니다. 상대방 키 또는 verisign과 같은 다른 관리자가 개입하여 제공되는 공개 키가 실제로 옳다고 말할 수 있습니다.

모든 OS의 신뢰는 소수의 인증 기관과 소규모 인증서 발급자는 내가 의미하는 바를 얻으면 인증 자 체인을 만드는 대형 인증 자 중 하나에 의해 인증되어야합니다.

어쨌든 요점으로 돌아와서 .. 나는 자바 애플릿과 자바 서버를 프로그래밍 할 때 비슷한 문제가 있었다. (언젠가는 내가 어떻게 모든 보안이 작동하는지에 대한 완전한 블로그 포스트를 쓸 것이다. :))

본질적으로 내가해야 할 일은 서버에서 공개 키를 추출하여 내 애플릿 내부의 키 저장소에 저장하는 것이었고 서버에 연결할 때이 키 저장소를 사용하여 트러스트 팩토리를 만들고 해당 트러스트 팩토리를 SSL을 만드는 데 사용했습니다. 연결. JVM의 신뢰할 수있는 호스트에 키를 추가하고 시작시 기본 신뢰 저장소를 수정하는 것과 같은 대체 절차도 있습니다.

나는 약 두 달 전에 이것을했고 지금은 나에게 소스 코드가 없다 .. 구글을 사용하면이 문제를 해결할 수있을 것이다. 저에게 다시 메시지를 보낼 수없고 프로젝트에 대한 관련 소스 코드를 제공 할 수 있다면 .. 이러한 예외를 발생시키는 코드를 제공하지 않았으므로 이것이 문제를 해결하는지 모르겠습니다. 또한 나는 애플릿으로 작업하고 있었는데 왜 Serverlets에서 작동하지 않는지 알 수 없다고 생각했습니다 …

추신 : 내 사무실에서 외부 SSH가 비활성화되어 있기 때문에 주말 전에 소스 코드를 얻을 수 없습니다.


답변

이제이 문제를 이렇게 해결했습니다.

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.OutputStream;
// Create a trust manager that does not validate certificate chains like the 
default TrustManager[] trustAllCerts = new TrustManager[] {
    new X509TrustManager() {
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
        }
        public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {
            //No need to implement. 
        }
        public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {
            //No need to implement. 
        }
    }
};
// Install the all-trusting trust manager
try {
    SSLContext sc = SSLContext.getInstance("SSL");
    sc.init(null, trustAllCerts, new java.security.SecureRandom());
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
    System.out.println(e);
}


답변