[java] javax.net.ssl.SSLHandshakeException 해결 : sun.security.validator.ValidatorException : PKIX 경로 빌드 실패 오류?

편집 :-블로그 에서 질문을 더 표현 가능한 방식으로 형식화하려고 시도했습니다.

원래 문제는 다음과 같습니다.

이 오류가 발생합니다.

자세한 메시지 sun.security.validator.ValidatorException : PKIX 경로 작성 실패 :
sun.security.provider.certpath.SunCertPathBuilderException : 요청 된 대상에 대한 유효한 인증 경로를 찾을 수 없습니다.

원인 javax.net.ssl.SSLHandshakeException : sun.security.validator.ValidatorException : PKIX 경로 작성 실패 : sun.security.provider.certpath.SunCertPathBuilderException : 요청 된 대상에 대한 유효한 인증 경로를 찾을 수 없습니다.

Tomcat 6을 웹 서버로 사용하고 있습니다. 다른 포트의 다른 Tomcat에 동일한 시스템에 두 개의 HTTPS 웹 응용 프로그램이 설치되어 있습니다. 말 App1(port 8443)
App2(port 443). App1에 연결합니다 App2. 에 App1연결할 때 App2위의 오류가 발생합니다. 나는 이것이 매우 일반적인 오류이므로 다른 포럼과 사이트의 많은 솔루션을 발견했습니다. server.xml두 Tomcat 에 아래 항목이 있습니다 .

keystoreFile="c:/.keystore"
keystorePass="changeit"

모든 사이트는 app2가 제공 한 인증서가 app1 jvm의 신뢰할 수있는 저장소에없는 것과 같은 이유를 말합니다. IE 브라우저에서 동일한 URL을 누르려고 할 때도 마찬가지입니다.이 웹 사이트의 보안 인증서에 문제가 있습니다.이 웹 사이트를 계속 진행하십시오. 그러나 동일한 URL이 Java 클라이언트 (내 경우)에 충돌하면 위의 오류가 발생합니다. 그래서 그것을 신뢰 저장소에 넣으려면 다음 세 가지 옵션을 시도했습니다.

옵션 1

System.setProperty("javax.net.ssl.trustStore", "C:/.keystore");
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");

옵션 2
환경 변수에서 아래 설정

CATALINA_OPTS -- param name
-Djavax.net.ssl.trustStore=C:\.keystore -Djavax.net.ssl.trustStorePassword=changeit ---param value

옵션 3
환경 변수에서 아래 설정

JAVA_OPTS -- param name
-Djavax.net.ssl.trustStore=C:\.keystore -Djavax.net.ssl.trustStorePassword=changeit ---param value

그러나 아무것도 효과가 없었습니다 .

마지막 으로 Apache HttpClient로 유효하지 않은 SSL 인증서를 처리하는 방법에서 제안 된 Java 접근 방식을 실행하고 있습니까? Pascal Thivent에 의해, 즉 InstallCert 프로그램을 실행합니다.

그러나이 방법은 devbox 설정에는 적합하지만 프로덕션 환경에서는 사용할 수 없습니다.

나는 동일한 값을 언급 할 때 세 가지 방법은 위의 일을하지 않았다 언급 왜 궁금 server.xmlapp2설정에 의해 신뢰 저장소에 서버와 같은 값

System.setProperty("javax.net.ssl.trustStore", "C:/.keystore") and System.setProperty("javax.net.ssl.trustStorePassword", "changeit");

에서 app1프로그램.

자세한 내용은 연결 방법입니다.

URL url = new URL(urlStr);

URLConnection conn = url.openConnection();

if (conn instanceof HttpsURLConnection) {

  HttpsURLConnection conn1 = (HttpsURLConnection) url.openConnection();

  conn1.setHostnameVerifier(new HostnameVerifier() {
    public boolean verify(String hostname, SSLSession session) {
      return true;
    }
  });

  reply.load(conn1.getInputStream());



답변

에 위치한 사용 된 JVM의 신뢰 저장소 파일에 App2 에 대한 인증서를 추가해야합니다 %JAVA_HOME%\lib\security\cacerts.

먼저 다음 명령을 실행하여 인증서가 이미 신뢰 저장소에 있는지 확인할 수 있습니다.
keytool -list -keystore "%JAVA_HOME%/jre/lib/security/cacerts"(비밀번호를 제공 할 필요가 없습니다)

인증서가 누락 된 경우 브라우저로 인증서를 다운로드하여 얻을 수 있으며 다음 명령을 사용하여 신뢰 저장소에 추가하십시오.

keytool -import -noprompt -trustcacerts -alias <AliasName> -file <certificate> -keystore <KeystoreFile> -storepass <Password>

가져온 후 첫 번째 명령을 다시 실행하여 인증서가 추가되었는지 확인할 수 있습니다.

Sun / Oracle 정보는 여기를 참조하십시오 .


답변

javax.net.ssl.SSLHandshakeException : sun.security.validator.ValidatorException : PKIX 경로 작성 실패 : sun.security.provider.certpath.SunCertPathBuilderException : 요청 된 대상에 대한 유효한 인증 경로를 찾을 수 없습니다.

• 오류가 발생했을 때 Google에서 표현식의 의미를 알아 내려고했지만 서버에서 HTTPS SSL 인증서를 변경하고 이전 버전의 java가 루트 인증 기관 (CA)을 인식하지 못하는 경우이 문제가 발생합니다. .

• 브라우저에서 HTTPS URL에 액세스 할 수 있으면 루트 CA를 인식하도록 Java를 업데이트 할 수 있습니다.

• 브라우저에서 Java가 액세스 할 수없는 HTTPS URL로 이동하십시오. HTTPS 인증서 체인 (Internet Explorer에 잠금 아이콘이 있음)을 클릭하고 잠금을 클릭하여 인증서를보십시오.

• 인증서의 “세부 사항”및 “파일로 복사”로 이동하십시오. Base64 (.cer) 형식으로 복사하십시오 . 데스크탑에 저장됩니다.

• 모든 경고를 무시하고 인증서를 설치하십시오.

• 액세스하려는 URL의 인증서 정보를 수집 한 방법입니다.

이제 인증서에 대해 알 수 있도록 Java 버전을 만들어야 URL이 더 이상 인식되지 않습니다. 이와 관련하여 루트 인증서 정보가 기본적으로 JDK의 \ jre \ lib \ security 위치에 유지되며 액세스 할 기본 비밀번호는 changeit입니다.

cacerts 정보를 보려면 다음 절차를 따르십시오.

• 시작 버튼-> 실행을 클릭하십시오.

• cmd를 입력하십시오. 명령 프롬프트가 열립니다 (관리자로 열어야 할 수도 있음).

Java/jreX/bin디렉토리로 이동

• 다음을 입력하십시오

keytool -list -keystore D : \ Java \ jdk1.5.0_12 \ jre \ lib \ security \ cacerts

키 저장소에 포함 된 현재 인증서 목록을 제공합니다. 다음과 같이 보입니다 :

C : \ Documents and Settings \ NeelanjanaG> keytool -list -keystore D : \ Java \ jdk1.5.0_12 \ jre \ lib \ security \ cacerts

키 저장소 비밀번호 입력 : changeit

키 스토어 타입 : JKS

키 스토어 제공 업체 : SUN

키 저장소에 44 개의 항목이 있습니다.

verisignclass3g2ca, 2004 년 3 월 26 일, trustedCertEntry,

인증서 지문 (MD5) : A2 : 33 : 9B : 4C : 74 : 78 : 73 : D4 : 6C : E7 : C1 : F3 : 8D : CB : 5C : E9

entrustclientca, 2003 년 1 월 9 일, trustedCertEntry,

인증서 지문 (MD5) : 0C : 41 : 2F : 13 : 5B : A0 : 54 : F5 : 96 : 66 : 2D : 7E : CD : 0E : 03 : F4

thawtepersonalbasicca, 1999 년 2 월 13 일, trustedCertEntry,

인증서 지문 (MD5) : E6 : 0B : D2 : C9 : CA : 2D : 88 : DB : 1A : 71 : 0E : 4B : 78 : EB : 02 : 41

addtrustclass1ca, 2006 년 5 월 1 일, trustedCertEntry,

인증서 지문 (MD5) : 1E : 42 : 95 : 02 : 33 : 92 : 6B : B9 : 5F : C0 : 7F : DA : D6 : B2 : 4B : FC

verisignclass2g3ca, 2004 년 3 월 26 일, trustedCertEntry,

인증서 지문 (MD5) : F8 : BE : C4 : 63 : 22 : C9 : A8 : 46 : 74 : 8B : B8 : 1D : 1E : 4A : 2B : F6

• 이제 이전에 설치된 인증서를 cacert에 포함시켜야했습니다.

•이를위한 절차는 다음과 같습니다.

keytool –import –noprompt –trustcacerts –alias ALIASNAME-파일 FILENAME_OF_THE_INSTALLED_CERTIFICATE -keystore PATH_TO_CACERTS_FILE -storepass PASSWORD

Java 7을 사용중인 경우 :

keytool –importcert –trustcacerts –alias ALIASNAME-파일 PATH_TO_FILENAME_OF_THE_INSTALLED_CERTIFICATE -keystore PATH_TO_CACERTS_FILE -storepass changeit

그런 다음 인증서 정보를 cacert 파일에 추가합니다.

위에서 언급 한 예외에 대해 찾은 솔루션입니다!


답변

Tomcat 7에서 작동하는 방법

Tomcat 앱에서 자체 서명 된 인증서를 지원하고 싶었지만 다음 스 니펫이 작동하지 않았습니다.

import java.io.DataOutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class HTTPSPlayground {
    public static void main(String[] args) throws Exception {

        URL url = new URL("https:// ... .com");
        HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();

        httpURLConnection.setRequestMethod("POST");
        httpURLConnection.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
        httpURLConnection.setDoOutput(true);
        DataOutputStream wr = new DataOutputStream(httpURLConnection.getOutputStream());

        String serializedMessage = "{}";
        wr.writeBytes(serializedMessage);
        wr.flush();
        wr.close();

        int responseCode = httpURLConnection.getResponseCode();
        System.out.println(responseCode);
    }
}

이것이 내 문제를 해결 한 것입니다.

1) .crt파일 다운로드

echo -n | openssl s_client -connect <your domain>:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ~/<your domain>.crt
  • 대체 <your domain>도메인으로 (예를 들어 jossef.com)

2) .crt파일을 Java cacerts인증서 저장소 에 적용하십시오.

keytool -import -v -trustcacerts -alias <your domain> -file ~/<your domain>.crt -keystore <JAVA HOME>/jre/lib/security/cacerts -keypass changeit -storepass changeit
  • 대체 <your domain>도메인으로 (예를 들어 jossef.com)
  • <JAVA HOME>자바 홈 디렉토리로 교체

3) 해킹

iv Java는 기본 인증서 저장소에 인증서를 설치했지만 Tomcat은이를 무시합니다 (Java의 기본 인증서 저장소를 사용하도록 구성되지 않은 것으로 보입니다).

이것을 해킹하려면 코드 어딘가에 다음을 추가하십시오.

String certificatesTrustStorePath = "<JAVA HOME>/jre/lib/security/cacerts";
System.setProperty("javax.net.ssl.trustStore", certificatesTrustStorePath);

// ...


답변

필자의 경우 문제는 웹 서버가 루트 CA가 아닌 인증서와 중간 CA 만 보내는 것입니다. 이 JVM 옵션을 추가하면 문제가 해결되었습니다.-Dcom.sun.security.enableAIAcaIssuers=true

기관 정보 액세스 확장의 CaIssuers 액세스 방법에 대한 지원이 제공됩니다. 호환성을 위해 기본적으로 비활성화되어 있으며 시스템 속성 com.sun.security.enableAIAcaIssuers을 true 로 설정하여 활성화 할 수 있습니다 .

true로 설정하면 Sun의 CertPathBuilder PKIX 구현은 인증서의 AIA 확장 (지정된 CertStores와 함께)의 정보를 사용하여 발급 CA 인증서를 찾습니다 (ldap, http 또는 ftp 유형의 URI 인 경우).

출처


답변

또 다른 이유는 JDK의 오래된 버전 일 수 있습니다. jdk 버전 1.8.0_60을 사용하고 있었고 최신 버전으로 업데이트하면 인증서 문제가 해결되었습니다.


답변

내 cacerts 파일이 완전히 비어있었습니다. cacerts 파일을 Windows 시스템 (Oracle Java 7을 사용하는)에서 복사하여 Linux 상자 (OpenJDK)에 scp했습니다.

cd %JAVA_HOME%/jre/lib/security/
scp cacerts mylinuxmachin:/tmp

그리고 리눅스 머신에서

cp /tmp/cacerts /etc/ssl/certs/java/cacerts

지금까지 훌륭하게 작동했습니다.


답변

나 에게이 오류는 SSL을 처리하는 NGINX 리버스 프록시 뒤의 프로세스에 연결하려고 할 때도 나타납니다.

문제는 전체 인증서 체인이 연결되지 않은 인증서라는 것이 밝혀졌습니다. 중간 인증서를 추가하면 문제가 해결되었습니다.

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