[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.xml
의 app2
설정에 의해 신뢰 저장소에 서버와 같은 값
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 리버스 프록시 뒤의 프로세스에 연결하려고 할 때도 나타납니다.
문제는 전체 인증서 체인이 연결되지 않은 인증서라는 것이 밝혀졌습니다. 중간 인증서를 추가하면 문제가 해결되었습니다.
도움이 되었기를 바랍니다.