Java : sun.security.provider.certpath.SunCertPathBuilderException : 요청한 대상에 대한 유효한 인증 경로를 찾을 수 없습니다


250

https 서버 에서 파일을 다운로드하는 클래스가 있습니다. 실행할 때 많은 오류가 발생합니다. 인증서에 문제가있는 것 같습니다. 클라이언트-서버 인증을 무시할 수 있습니까? 그렇다면 어떻게?

package com.da;

import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.CharBuffer;
import java.util.concurrent.Future;

import org.apache.http.HttpResponse;
import org.apache.http.client.utils.URIUtils;
import org.apache.http.impl.nio.client.DefaultHttpAsyncClient;
import org.apache.http.nio.IOControl;
import org.apache.http.nio.client.HttpAsyncClient;
import org.apache.http.nio.client.methods.AsyncCharConsumer;
import org.apache.http.nio.client.methods.HttpAsyncGet;
import org.apache.http.nio.client.methods.HttpAsyncPost;

public class RSDDownloadFile {
    static FileOutputStream fos;

    public void DownloadFile(String URI, String Request) throws Exception
    {
        java.net.URI uri = URIUtils.createURI("https", "176.66.3.69:6443", -1, "download.aspx",
                "Lang=EN&AuthToken=package", null);
        System.out.println("URI Query: " + uri.toString());

        HttpAsyncClient httpclient = new DefaultHttpAsyncClient();
        httpclient.start();
        try {
            Future<Boolean> future = httpclient.execute(
                    new HttpAsyncGet(uri),
                    new ResponseCallback(), null);

            Boolean result = future.get();
            if (result != null && result.booleanValue()) {
                System.out.println("\nRequest successfully executed");
            } else {
                System.out.println("Request failed");
            }              
        } 
        catch(Exception e){
            System.out.println("[DownloadFile] Exception: " + e.getMessage());
        }
        finally {
            System.out.println("Shutting down");
            httpclient.shutdown();
        }
        System.out.println("Done");  

    }

    static class ResponseCallback extends AsyncCharConsumer<Boolean> {

        @Override
        protected void onResponseReceived(final HttpResponse response) {
             System.out.println("Response: " + response.getStatusLine());
             System.out.println("Header: " + response.toString());
             try {   
                 //if(response.getStatusLine().getStatusCode()==200)
                     fos = new FileOutputStream( "Response.html" );
             }catch(Exception e){
                 System.out.println("[onResponseReceived] Exception: " + e.getMessage());
             }
        }

        @Override
        protected void onCharReceived(final CharBuffer buf, final IOControl ioctrl) throws IOException {
            try
            {
                while (buf.hasRemaining()) 
                {
                    //System.out.print(buf.get());
                    fos.write(buf.get());
                }
            }catch(Exception e)
            {
                System.out.println("[onCharReceived] Exception: " + e.getMessage());
            }
        }

        @Override
        protected void onCleanup() {
            try
            {             
                if(fos!=null)
                    fos.close();
            }catch(Exception e){
                System.out.println("[onCleanup] Exception: " + e.getMessage());         
            }
             System.out.println("onCleanup()");
        }

        @Override
        protected Boolean buildResult() {
            return Boolean.TRUE;
        }

    }
}

오류 :

URI Query: https://176.66.3.69:6443/download.aspx?Lang=EN&AuthToken=package
Aug 2, 2011 3:47:57 PM org.apache.http.impl.nio.client.NHttpClientProtocolHandler exception
SEVERE: I/O error: General SSLEngine problem
javax.net.ssl.SSLHandshakeException: General SSLEngine problem
    at com.sun.net.ssl.internal.ssl.Handshaker.checkThrown(Unknown Source)
    at com.sun.net.ssl.internal.ssl.SSLEngineImpl.checkTaskThrown(Unknown Source)
    at com.sun.net.ssl.internal.ssl.SSLEngineImpl.writeAppRecord(Unknown Source)
    at com.sun.net.ssl.internal.ssl.SSLEngineImpl.wrap(Unknown Source)
    at javax.net.ssl.SSLEngine.wrap(Unknown Source)
    at org.apache.http.impl.nio.reactor.SSLIOSession.doHandshake(SSLIOSession.java:154)
    at org.apache.http.impl.nio.reactor.SSLIOSession.isAppInputReady(SSLIOSession.java:276)
    at org.apache.http.impl.nio.client.InternalClientEventDispatch.inputReady(InternalClientEventDispatch.java:79)
    at org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:161)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:335)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:315)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:275)
    at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:104)
    at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:542)
    at java.lang.Thread.run(Unknown Source)
Caused by: javax.net.ssl.SSLHandshakeException: General SSLEngine problem
    at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
    at com.sun.net.ssl.internal.ssl.SSLEngineImpl.fatal(Unknown Source)
    at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source)
    at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(Unknown Source)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(Unknown Source)
    at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Unknown Source)
    at com.sun.net.ssl.internal.ssl.Handshaker$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.net.ssl.internal.ssl.Handshaker$DelegatedTask.run(Unknown Source)
    at org.apache.http.impl.nio.reactor.SSLIOSession.doHandshake(SSLIOSession.java:180)
    ... 9 more
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.validator.PKIXValidator.doBuild(Unknown Source)
    at sun.security.validator.PKIXValidator.engineValidate(Unknown Source)
    at sun.security.validator.Validator.validate(Unknown Source)
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source)
    at com.sun.net.ssl.internal.ssl.JsseX509TrustManager.checkServerTrusted(Unknown Source)
    ... 16 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(Unknown Source)
    at java.security.cert.CertPathBuilder.build(Unknown Source)
    ... 21 more
onCleanup()

[DownloadFile] Exception: javax.net.ssl.SSLHandshakeException: General SSLEngine problem
Shutting down
Done

2
한 번이 오류가 발생하여 보안 팀에 문의 한 결과 팀에서 회사가 제공 한 오래된 파일을 사용하고 있으므로 사용중인 JAR을 패치해야하는 것으로 나타났습니다. 비슷한 상황에 처한 다른 사람들을위한 참고 자료입니다.
kayleeFrye_onDeck

답변:


215

서버에 자체 서명 된 인증서가있는 경우 문제가 나타납니다. 이를 해결하기 위해이 인증서를 JVM의 신뢰할 수있는 인증서 목록에 추가 할 수 있습니다.

이 기사에서는 브라우저에서 인증서를 가져 와서 JVM의 cacerts 파일에 추가하는 방법에 대해 설명합니다. JAVA_HOME/jre/lib/security/cacerts파일을 편집 하거나 -Djavax.net.ssl.trustStore매개 변수 를 사용하여 응용 프로그램을 실행할 수 있습니다 . 혼동의 원인이되기 때문에 어떤 JDK / JRE를 사용하고 있는지 확인하십시오.

참조 : SSL 인증서 서버 이름은 어떻게 확인됩니까 / keytool을 사용하여 대체 이름을 추가 할 수 있습니까? java.security.cert.CertificateException: No name matching localhost found예외가 발생한 경우


3
이것은 나를 위해 작동하지 않았습니다. 루트 및 체인 인증서가 설치되어 있지만 Tomcat-7은 여전히 ​​"요청한 대상에 대한 유효한 인증 경로를 찾을 수 없음"으로 인해 validatorException을보고하여이를 디버그 할 수 있습니까?
Cheruvim

신뢰할 수없는 다른 사람이 서명 한 인증서에 문제가 나타납니다.
Lorne의 후작

큰! 효과가있다! jre와 jdk를 모두 가질 수 있다는 것을 잊지 마십시오. 둘 다 cacerts업데이트되어야합니다.
Dima Fomin

제 경우에는 루트 CA가 있었지만 다음 CA는 다운되지 않았습니다. 다음 CA를 추가하면 문제가 해결되었습니다. 감사합니다.
java-addict301

1
필자의 경우 Netbeans + Apache Tomcat (통합)을 사용하고 있으므로 Jdk / jre의 신뢰 저장소 "cacerts"에 .cer를 추가합니다 (C : \ Program Files \ Java \ jdk1.8.0_152 \ jre \ lib \ 보안) 및 Jre (C : \ Program Files \ Java \ jre1.8.0_91 \ lib \ security)가 작동합니다.
Jnn

149

macOS에서 안정적으로 작동하는 것은 다음과 같습니다. example.com 및 443을 연결하려는 실제 호스트 이름 및 포트로 바꾸고 사용자 지정 별칭을 지정하십시오. 첫 번째 명령은 원격 서버에서 제공된 인증서를 다운로드하여 x509 형식으로 로컬로 저장합니다. 두 번째 명령은 저장된 인증서를 Java의 SSL 신뢰 저장소로로드합니다.

openssl x509 -in <(openssl s_client -connect example.com:443 -prexit 2>/dev/null) -out ~/example.crt
sudo keytool -importcert -file ~/example.crt -alias example -keystore $(/usr/libexec/java_home)/jre/lib/security/cacerts -storepass changeit

3
왜 작동합니까? 설명을 제공해야합니다.
Lorne의 후작

openssl x509 -in <(openssl s_client -connect example.com:443 -prexit 2> / dev / null) -out ~ / example.crt-명령에 example.crt 란 무엇입니까? .pem 인증서가 있습니다. 그게 여기에 ??
Vishnu Ranganathan

3
.crt 및 .pem은 동일한 파일 형식에 일반적으로 사용되는 파일 확장자입니다. 파일이 이미 있으면 두 번째 명령을 실행하여 -file 인수에 전달하십시오.
Gabe Martin-Dempesy

1
좋은 물건. 유일한 것은 : 어떤 이유로 최신 openssl 1.0.Xx를 사용해야했지만 이전 9.X.Xx가 작동하지 않았습니다.
zbstof 2016 년

1
SNI 엔드 포인트에서는 작동하지 않습니다. 이 경우 인증서를 가져올 때 -servername example.com을 추가해야합니다.
Patrik Beck

46

symantec의 유효한 서명 된 와일드 카드 인증서와 동일한 문제가있었습니다.

먼저 -Djavax.net.debug = SSL 을 사용하여 Java 애플리케이션을 실행하여 실제로 진행중인 작업을 확인하십시오.

결국 인증서 체인이 중단되는 중간 인증서가져 왔습니다.

symantec에서 누락 된 중간 인증서를 다운로드했습니다 (ssl 핸드 셰이크 로그에서 누락 된 인증서에 대한 다운로드 링크를 볼 수 있습니다 : http://svrintl-g3-aia.verisign.com/SVRIntlG3.cer ).

그리고 Java 키 저장소에서 인증서를 가져 왔습니다. 중간 인증서를 가져온 후 와일드 카드 SSL 인증서가 마침내 작동하기 시작했습니다.

keytool -import -keystore ../jre/lib/security/cacerts -trustcacerts -alias "VeriSign Class 3 International Server CA - G3" -file /pathto/SVRIntlG3.cer


2
혼동을 피하기 위해 디버그 매개 변수와 함께 java (또는 jcurl)를 실행하여 로그에서 원격 "인증서 체인"을 확인한 후 다음과 같이 명시 적으로 전달 된 신뢰 저장소에서 "CN"을 명시 적으로 전달하십시오 (없는 경우). 추가해야합니다. ssllabs.com/ssltest/analyze.html 은 서버 측 인증서에 불완전한 체인이 있는지 표시하고 추가해야하는 중간 인증 경로 인증서를 포함합니다. -Djavax.net.debug=ssl,handshake -Djavax.net.ssl.keyStoreType=PKCS12 -Djavax.net.ssl.keyStore=our-client-certs -Djavax.net.ssl.trustStoreType=jks -Djavax.net.ssl.trustStore=their-server-certs
kisna


나는 같은 문제가 있었는데 이것은 매우 유용하지만 제 경우에는 JDK 버전의 cacerts 파일에 서버 인증서 만 추가하면됩니다
Pigritia

cacert 파일 (인증서 저장소)을 열고 인증서를 쉽게 가져올 수있는 portecle이라는 다른 도구가 있습니다. 나중에 cacert 파일을 저장하십시오.
will824

41
  1. Firefox를 사용하여 SSL 인증서를 내 보냅니다. 브라우저에서 URL을 눌러 내보내고 인증서를 내보내는 옵션을 선택할 수 있습니다. 인증서 파일 이름이 your.ssl.server.name.crt 라고 가정합니다.
  2. 당신의 JRE_HOME/bin또는JDK/JRE/bin
  3. 명령을 입력하십시오
  4. keytool -keystore ..\lib\security\cacerts -import -alias your.ssl.server.name -file .\relative-path-to-cert-file\your.ssl.server.name.crt
  5. Java 프로세스를 다시 시작하십시오.

13
비밀번호를 묻는 경우 기본 cacerts 키 저장소 비밀번호 changeit( stackoverflow.com/a/22782035/1304830 )를 사용하십시오. 또한 관리자 권한으로 cmd를 실행하십시오.
Fr4nz

22

@Gabe Martin-Dempesy의 답변이 저에게 도움이됩니다. 그리고 나는 그것에 관련된 작은 스크립트를 썼습니다. 사용법은 매우 간단합니다.

호스트에서 인증서를 설치하십시오.

> sudo ./java-cert-importer.sh example.com

이미 설치된 인증서를 제거하십시오.

> sudo ./java-cert-importer.sh example.com --delete

java-cert-importer.sh

#!/usr/bin/env bash

# Exit on error
set -e

# Ensure script is running as root
if [ "$EUID" -ne 0 ]
  then echo "WARN: Please run as root (sudo)"
  exit 1
fi

# Check required commands
command -v openssl >/dev/null 2>&1 || { echo "Required command 'openssl' not installed. Aborting." >&2; exit 1; }
command -v keytool >/dev/null 2>&1 || { echo "Required command 'keytool' not installed. Aborting." >&2; exit 1; }

# Get command line args
host=$1; port=${2:-443}; deleteCmd=${3:-${2}}

# Check host argument
if [ ! ${host} ]; then
cat << EOF
Please enter required parameter(s)

usage:  ./java-cert-importer.sh <host> [ <port> | default=443 ] [ -d | --delete ]

EOF
exit 1
fi;

if [ "$JAVA_HOME" ]; then
    javahome=${JAVA_HOME}
elif [[ "$OSTYPE" == "linux-gnu" ]]; then # Linux
    javahome=$(readlink -f $(which java) | sed "s:bin/java::")
elif [[ "$OSTYPE" == "darwin"* ]]; then # Mac OS X
    javahome="$(/usr/libexec/java_home)/jre"
fi

if [ ! "$javahome" ]; then
    echo "WARN: Java home cannot be found."
    exit 1
elif [ ! -d "$javahome" ]; then
    echo "WARN: Detected Java home does not exists: $javahome"
    exit 1
fi

echo "Detected Java Home: $javahome"

# Set cacerts file path
cacertspath=${javahome}/lib/security/cacerts
cacertsbackup="${cacertspath}.$$.backup"

if ( [ "$deleteCmd" == "-d" ] || [ "$deleteCmd" == "--delete" ] ); then
    sudo keytool -delete -alias ${host} -keystore ${cacertspath} -storepass changeit
    echo "Certificate is deleted for ${host}"
    exit 0
fi

# Get host info from user
#read -p "Enter server host (E.g. example.com) : " host
#read -p "Enter server port (Default 443) : " port

# create temp file
tmpfile="/tmp/${host}.$$.crt"

# Create java cacerts backup file
cp ${cacertspath} ${cacertsbackup}

echo "Java CaCerts Backup: ${cacertsbackup}"

# Get certificate from speficied host
openssl x509 -in <(openssl s_client -connect ${host}:${port} -prexit 2>/dev/null) -out ${tmpfile}

# Import certificate into java cacerts file
sudo keytool -importcert -file ${tmpfile} -alias ${host} -keystore ${cacertspath} -storepass changeit

# Remove temp certificate file
rm ${tmpfile}

# Check certificate alias name (same with host) that imported successfully
result=$(keytool -list -v -keystore ${cacertspath} -storepass changeit | grep "Alias name: ${host}")

# Show results to user
if [ "$result" ]; then
    echo "Success: Certificate is imported to java cacerts for ${host}";
else
    echo "Error: Something went wrong";
fi;

완벽하게 작동합니다. 잘 했어! . 작동 방식 : SSL 서비스를 시작하고 (실행 중이 아닌 경우) 설명 된대로 명령을 실행하십시오 (예 :) ./java-cert-importer.sh example.com 1234. 그게 다야.
lepe

1
잘 작동합니다. 인증서를 변경하고 빌드에 실패하는 외부 API에 연결하는 Jenkins 서버에서 오류가 발생했습니다. 이것은 내 문제를 해결합니다
user9869932

오라클은 처음에 이와 같은 것을 제공했거나 모두 자신의 끔찍한 SSL 솔루션을 만들지 않았어야합니다. SSL 인증서 처리는 운영 체제의 작업이어야합니다.
Wolfgang Fahl

17

더 이상 '요청한 대상에 대한 유효한 인증 경로를 찾을 수 없습니다' 에서 인용

JSSE를 사용하여 호스트에 대한 SSL 연결을 열려고 할 때. 이것은 일반적으로 서버가 Verisign 또는 GoDaddy와 같은 잘 알려진 상용 인증 기관의 인증서가 아닌 테스트 인증서 (keytool을 사용하여 생성)를 사용하고 있음을 의미합니다. 이 경우 웹 브라우저는 경고 대화 상자를 표시하지만 JSSE는 대화식 사용자가 있다고 가정 할 수 없으므로 기본적으로 예외가 발생합니다.

인증서 유효성 검사는 SSL 보안에서 매우 중요한 부분이지만 자세한 내용을 설명하기 위해이 항목을 작성하지는 않습니다. 관심이 있으시면 Wikipedia blurb를 읽으십시오. 원하는 경우 테스트 인증서로 해당 호스트와 대화하는 간단한 방법을 보여주기 위해이 항목을 작성하고 있습니다.

기본적으로 신뢰할 수있는 인증서를 사용하여 서버의 인증서를 키 저장소에 추가하려고합니다.

제공된 코드를 사용해보십시오. 도움이 될 수 있습니다.


5
"인증서 유효성 검사는 SSL 보안에서 매우 중요한 부분"에 관한 부분이 반드시 사실은 아닙니다. SSL은 (1) 귀하의 의사 소통은 비공개이며 (2) NSA에 알려진 서버와 대화하고 있다는 두 가지 보증을 제공합니다. 자체 서명 인증은 괜찮습니다.
AgilePro

@AgilePro SSL은 인증, 개인 정보 보호, 무결성 및 권한 부여의 네 가지 보증을 제공합니다 . NSA에 알려진 서버와 통신하고 있다는 보장 은 없습니다 . 인증없이 개인 정보 보호만을 고려하는 것은 용어의 모순입니다.
Lorne의 후작

@EJP 클라이언트 인증서를 사용하는 경우 인증을받을 수 있으며 인증 가능성이 있다고 생각하지만 대부분의 용도는 클라이언트 인증서와는 다릅니다. "자체 서명 된"인증서와 서명 기관의 인증서의 차이점을 무엇이라고 하시겠습니까? 서명 권한은 "무결성"을 제공합니다. NSA에 대한 농담은 모든 서명 기관이 모든 것과의 독립성을 긍정적으로 보장 할 수는 없다는 것입니다. 그 편집증은 실제로는 아니지만 서명 기관이 할 수있는 한 인증서 만 비밀입니다. 자체 서명은 더 비밀이 될 수 있습니다.
AgilePro

사용 @AgilePro 서버 인증서는 서버를 인증하고 필요한 인증서는 전혀 비밀이 아니다 RFC 2246에 명시된 바와 같이, SSL을 확보하기 위해 : 당신의 코멘트 때문에 나머지는 이해되지 않는다.
Lorne의 후작

6

이것은 내 문제를 해결했다.

인증서를 로컬 Java로 가져와야합니다. 그렇지 않다면 아래 예외를 얻을 수 있습니다.

    javax.net.ssl.SSLHandshakeException : sun.security.validator.ValidatorException : PKIX 경로 작성 실패 : sun.security.provider.certpath.SunCertPathBuilderException : 요청 된 대상에 대한 유효한 인증 경로를 찾을 수 없습니다.
        sun.security.ssl.Alerts.getSSLException (Alerts.java:192)에서
        sun.security.ssl.SSLSocketImpl.fatal (SSLSocketImpl.java:1949)에서
        sun.security.ssl.Handshaker.fatalSE에서 (Handshaker.java:302)

SSLPOKE 는 로컬 컴퓨터에서 https 연결을 테스트 할 수있는 도구입니다.

연결성을 테스트하는 명령 :

"%JAVA_HOME%/bin/java" SSLPoke <hostname> 443
    sun.security.validator.ValidatorException : PKIX 경로 작성에 실패했습니다 : 
    sun.security.provider.certpath.SunCertPathBuilderException : 요청한 대상에 대한 유효한 인증 경로를 찾을 수 없습니다
        sun.security.validator.PKIXValidator.doBuild (PKIXValidator.java:387)에서
        sun.security.validator.PKIXValidator.engineValidate (PKIXValidator.java:292)에서
        sun.security.validator.Validator.validate (Validator.java:260)에서
        sun.security.ssl.X509TrustManagerImpl.validate (X509TrustManagerImpl.java:324)에서
        sun.security.ssl.X509TrustManagerImpl.checkTrusted (X509TrustManagerImpl.java:229)에서
        sun.security.ssl.X509TrustManagerImpl.checkServerTrusted (X509TrustManagerImpl.java:124)에서
        sun.security.ssl.ClientHandshaker.serverCertificate (ClientHandshaker.java:1496)에서
        sun.security.ssl.ClientHandshaker.processMessage (ClientHandshaker.java:216)에서
        sun.security.ssl.Handshaker.processLoop (Handshaker.java:1026)에서
        sun.security.ssl.Handshaker.process_record (Handshaker.java:961)에서
        sun.security.ssl.SSLSocketImpl.readRecord (SSLSocketImpl.java:1062)에서
        sun.security.ssl.SSLSocketImpl.performInitialHandshake (SSLSocketImpl.java:1375)에서
        sun.security.ssl.SSLSocketImpl.writeRecord (SSLSocketImpl.java:747)에서
        sun.security.ssl.AppOutputStream.write (AppOutputStream.java:123)에서
        sun.security.ssl.AppOutputStream.write (AppOutputStream.java:138)에서
        SSLPoke.main (SSLPoke.java:31)에서
    원인 : sun.security.provider.certpath.SunCertPathBuilderException : 유효한 인증 경로를 찾을 수 없습니다. 
    요청한 대상
        sun.security.provider.certpath.SunCertPathBuilder.build (SunCertPathBuilder.java:141)에서
        sun.security.provider.certpath.SunCertPathBuilder.engineBuild (SunCertPathBuilder.java:126)에서
        java.security.cert.CertPathBuilder.build (CertPathBuilder.java:280)에서
        sun.security.validator.PKIXValidator.doBuild (PKIXValidator.java:382)에서
        ... 15 더보기
keytool -import -alias <anyname> -keystore "%JAVA_HOME%/jre/lib/security/cacerts" -file <cert path>

먼저 "키 저장소 비밀번호 입력 :" changeit이 기본 비밀번호입니다. 마지막으로 "이 인증서를 신뢰 하시겠습니까? [no] :"라는 프롬프트가 표시되면 "yes"를 제공하여 인증서를 키 저장소에 추가하십시오.

검증 :

C:\tools>"%JAVA_HOME%/bin/java" SSLPoke <hostname> 443
Successfully connected    

5

코드로만 작동시킬 수있었습니다. 즉 keytool을 사용할 필요가 없습니다.

import com.netflix.config.DynamicBooleanProperty;
import com.netflix.config.DynamicIntProperty;
import com.netflix.config.DynamicPropertyFactory;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;
import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
import org.apache.http.impl.nio.reactor.IOReactorConfig;
import org.apache.http.nio.conn.NoopIOSessionStrategy;
import org.apache.http.nio.conn.SchemeIOSessionStrategy;
import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

public class Test
{
    private static final DynamicIntProperty MAX_TOTAL_CONNECTIONS = DynamicPropertyFactory.getInstance().getIntProperty("X.total.connections", 40);
    private static final DynamicIntProperty ROUTE_CONNECTIONS = DynamicPropertyFactory.getInstance().getIntProperty("X.total.connections", 40);
    private static final DynamicIntProperty CONNECT_TIMEOUT = DynamicPropertyFactory.getInstance().getIntProperty("X.connect.timeout", 60000);
    private static final DynamicIntProperty SOCKET_TIMEOUT = DynamicPropertyFactory.getInstance().getIntProperty("X.socket.timeout", -1);
    private static final DynamicIntProperty CONNECTION_REQUEST_TIMEOUT = DynamicPropertyFactory.getInstance().getIntProperty("X.connectionrequest.timeout", 60000);
    private static final DynamicBooleanProperty STALE_CONNECTION_CHECK = DynamicPropertyFactory.getInstance().getBooleanProperty("X.checkconnection", true);

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

        SSLContext sslcontext = SSLContexts.custom()
                .useTLS()
                .loadTrustMaterial(null, new TrustStrategy()
                {
                    @Override
                    public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException
                    {
                        return true;
                    }
                })
                .build();
        SSLIOSessionStrategy sslSessionStrategy = new SSLIOSessionStrategy(sslcontext, new AllowAll());

        Registry<SchemeIOSessionStrategy> sessionStrategyRegistry = RegistryBuilder.<SchemeIOSessionStrategy>create()
                .register("http", NoopIOSessionStrategy.INSTANCE)
                .register("https", sslSessionStrategy)
                .build();

        DefaultConnectingIOReactor ioReactor = new DefaultConnectingIOReactor(IOReactorConfig.DEFAULT);
        PoolingNHttpClientConnectionManager connectionManager = new PoolingNHttpClientConnectionManager(ioReactor, sessionStrategyRegistry);
        connectionManager.setMaxTotal(MAX_TOTAL_CONNECTIONS.get());
        connectionManager.setDefaultMaxPerRoute(ROUTE_CONNECTIONS.get());

        RequestConfig requestConfig = RequestConfig.custom()
                .setSocketTimeout(SOCKET_TIMEOUT.get())
                .setConnectTimeout(CONNECT_TIMEOUT.get())
                .setConnectionRequestTimeout(CONNECTION_REQUEST_TIMEOUT.get())
                .setStaleConnectionCheckEnabled(STALE_CONNECTION_CHECK.get())
                .build();

        CloseableHttpAsyncClient httpClient = HttpAsyncClients.custom()
                .setSSLStrategy(sslSessionStrategy)
                .setConnectionManager(connectionManager)
                .setDefaultRequestConfig(requestConfig)
                .build();

        httpClient.start();

        // use httpClient...
    }

    private static class AllowAll implements X509HostnameVerifier
    {
        @Override
        public void verify(String s, SSLSocket sslSocket) throws IOException
        {}

        @Override
        public void verify(String s, X509Certificate x509Certificate) throws SSLException {}

        @Override
        public void verify(String s, String[] strings, String[] strings2) throws SSLException
        {}

        @Override
        public boolean verify(String s, SSLSession sslSession)
        {
            return true;
        }
    }
}

1
Btw, 나는 httpasyncclient : 4.0.1을 사용하고 있습니다
Jonas Bergström

SSLContext를 사용하는 솔루션이 많이 도움이되는 @ JonasBergström과 비슷한 것이 필요했습니다.
Enter SB

8
이 솔루션은 안전하지 않습니다.
Lorne의 후작

Jonas에게 감사합니다. 솔루션으로 문제가 해결되었습니다. 그러나 첫 번째 연결을 만드는 데 매우 오랜 시간 (3-5 초)이 걸린다는 것을 알았습니다. 그 후 모든 연결에는 300-400ms 만 필요합니다.
twcai

5

Comodo 와일드 카드 인증서를 사용하는 Apache 2.4 인스턴스에서이 오류의 원인은 SHA-1 서명 루트 인증서에 대한 불완전한 경로였습니다. 발급 된 인증서에 여러 체인이 있으며 SHA-1 루트 인증서로 연결되는 체인에 중간 인증서 가 누락되었습니다 . 최신 브라우저는이를 처리하는 방법을 알고 있지만 Java 7은 기본적으로이를 처리하지 않습니다 (코드에서이를 수행하는 몇 가지 복잡한 방법이 있지만). 결과는 자체 서명 된 인증서의 경우와 동일한 오류 메시지입니다.

Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:196)
    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:268)
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:380)
    ... 22 more

이 경우 중간 인증서가 누락되어 "요청한 대상에 대한 유효한 인증 경로를 찾을 수 없습니다"메시지가 생성됩니다. 서버에 대해 SSL Labs 테스트를 사용하여 누락 된 인증서를 확인할 수 있습니다 . 적절한 인증서를 찾으면 인증서를 다운로드하여 (서버가 제어하는 ​​경우) 인증서 번들에 추가하십시오. 또는 누락 된 인증서를 로컬로 가져올 수 있습니다. 서버에서이 문제를 해결하는 것이 문제에 대한보다 일반적인 해결책입니다.


ssllabs.com/ssltest 는 구세주입니다. 작동하는 인증서 확인과 비교하면됩니다.
kisna

5

Windows의 경우 다음 단계를 수행하십시오.

  1. Chrome에서 설정으로 이동하십시오.
  2. 설정에서 고급 설정 표시를 클릭하십시오.
  3. HTTPS / SSL에서 인증서 관리를 클릭하십시오.
  4. 인증서를 내 보냅니다.
  5. Windows 검색 (키보드에서 windows 키 누름)에서 java를 입력하십시오.
  6. Java 제어판을 여는 (Java 구성) 옵션을 선택하십시오.
  7. Java 제어판에서 보안 탭을 선택하십시오.
  8. 인증서 관리를 선택하십시오.
  9. 가져 오기를 클릭하십시오
  10. (사용자) 탭 아래에서 인증서 유형을 (신뢰할 수있는 인증서)로
  11. 가져 오기 단추를 클릭하고 다운로드 한 인증서를 찾아서 가져 오십시오.

4

데비안과 사전 패키지 된 Java를 좋아하는 사람들을 위해 :

sudo mkdir /usr/share/ca-certificates/test/  # don't mess with other certs
sudo cp ~/tmp/test.loc.crt /usr/share/ca-certificates/test/
sudo dpkg-reconfigure --force ca-certificates  # check your cert in curses GUI!
sudo update-ca-certificates --fresh --verbose

다음을 확인 /etc/default/cacerts하는 것을 잊지 마십시오 :

# enable/disable updates of the keystore /etc/ssl/certs/java/cacerts
cacerts_updates=yes

인증서를 제거하려면

sudo rm /usr/share/ca-certificates/test/test.loc.crt
sudo rm /etc/ssl/certs/java/cacerts
sudo update-ca-certificates --fresh --verbose

2

SHA2를 사용하여 서명 한 Java 7과 함께 GoDaddy 인증서를 사용하여 발생할 수도 있습니다.

Chrome 및 다른 모든 브라우저는 안전하지 않기 때문에 SHA1을 사용하여 서명 된 SSL 인증서를 더 이상 사용하지 않습니다.

이 문제에 대한 자세한 정보 는 여기 에서 찾을 수 있으며 지금 필요한 경우 서버에서 문제를 해결하는 방법도 있습니다.


2

인증서 오류와 동일한 문제가 있었고 SNI 때문이었습니다. 사용한 http 클라이언트에는 SNI가 구현되지 않았습니다. 그래서 버전 업데이트가 작업을 수행했습니다.

   <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.3.6</version>
    </dependency>

2

최신 정보: 재부팅이 도움이되었다는 것은 우연의 일이었습니다. 문제의 실제 원인은 다음과 같습니다. Gradle이 특정 키 저장소를 사용하도록 지시 할 때 해당 키 저장소에도 모든 공식 루트 인증서가 포함되어야합니다. 그렇지 않으면 일반 리포지토리에서 라이브러리에 액세스 할 수 없습니다. 내가해야했던 것은 이것이었다 :

자체 서명 된 인증서를 가져 오십시오.

keytool -import -trustcacerts -alias myselfsignedcert -file /Users/me/Desktop/selfsignedcert.crt -keystore ./privateKeystore.jks

공식 루트 인증서를 추가하십시오.

keytool -importkeystore -srckeystore <java-home>/lib/security/cacerts -destkeystore ./privateKeystore.jks

아마도 Gradle 데몬도 방해가 될 수 있습니다. ./gradlew --status상황이 어둡게 보이기 시작하면 발견 된 모든 데몬을 죽일 가치가 있습니다 .

원래 게시 :

아무도 이것을 믿지 않을 것입니다. 그래도 다른 모든 방법이 실패하면 다시 시도해보십시오. 재부팅 Mac을 문제가 해결되었습니다. Grrr.

배경 : ./gradlew jar가 계속 "요청한 대상에 대한 유효한 인증 경로를 찾을 수 없습니다"

브라우저에서 저장하고 privateKeystore.jks로 가져온 자체 서명 인증서가 붙어 있습니다. 그런 다음 Gradle에게 privateKeystore.jks를 사용하도록 지시했습니다.

org.gradle.jvmargs=-Djavax.net.debug=SSL -Djavax.net.ssl.trustStore="/Users/me/IntelliJ/myproject/privateKeystore.jks"  -Djavax.net.ssl.trustStorePassword=changeit

언급했듯이 이것은 재부팅 후에 만 ​​작동했습니다.


2

AVG 버전 18.1.3044 (Windows 10 포함)가 로컬 Spring 응용 프로그램을 방해합니다.

해결 방법 : "웹 및 이메일"이라는 AVG 섹션에 입력하고 "이메일 보호"를 비활성화하십시오. 사이트가 안전하지 않으면 AVG가 인증서를 차단합니다.


2

https://176.66.3.69:6443/ 에 유효한 인증서가 있는지 확인하십시오 . 브라우저 https는 안전하지 않습니다에서 작동하면 브라우저를 통해 먼저 확인할 수 있습니다 .Java 에서 작동합니다.

그것은 나를 위해 일하고있다


브라우저가 불만을 제기하면 어떻게해야합니까?
대부

인증서 설치 시도
Amr Ibrahim

2

이것을 해결하는 많은 방법이 있습니다 ...

한 가지 방법은 키 저장소 파일에 TrustStore 인증서를 설정하고이를 애플리케이션의 경로에 넣고 기본 방법으로 이러한 시스템 특성을 설정하는 것입니다.

public static void main(String[] args) {
  System.setProperty("javax.net.ssl.trustStore", "trust-store.jks");
  System.setProperty("javax.net.ssl.trustStorePassword", "TrustStore");
  ...
}

다른 방법은 키 저장소를 프로젝트 jar 파일 내에 리소스 파일로 배치하고로드하는 것입니다.

public static SSLContext createSSLContext(String resourcePath, String pass) throws NoSuchAlgorithmException, KeyStoreException, IOException, CertificateException, UnrecoverableKeyException, KeyManagementException {
  // initialise the keystore
  final char[] password = pass.toCharArray();
  KeyStore ks = KeyStore.getInstance("JKS");
  ks.load(ThisClass.class.getResourceAsStream(resourcePath
  ), password);

  // Setup the key manager factory.
  KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
  kmf.init(ks, password);

  // Setup the trust manager factory.
  TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
  tmf.init(ks);

  SSLContext sslc = SSLContext.getInstance("TLS");
  sslc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
  return sslc;
}

public static void main(String[] args) {
  SSLContext.setDefault(
    createSSLContext("/trust-store.jks", "TrustStore"));
  ...
}

Windows에서는이 솔루션을 사용해 볼 수도 있습니다 : https : //.com/a/59056537/980442


.crt이 방법으로 인증 기관 CA 파일에서 키 저장소 파일을 작성했습니다 .

keytool -import -alias ca -keystore trust-store.jks -storepass TrustStore -trustcacerts -file ca.crt

참고로 https://docs.oracle.com/javadb/10.8.3.0/adminguide/cadminsslclient.html


1

소프트웨어가 실행될 각 jvm에 대해 자체 서명 된 인증서를 Java의 키 저장소로 가져 오거나 유효성을 검사하지 않는 SSL 팩토리를 시도하는 두 가지 옵션이 있습니다.

jdbc:postgresql://myserver.com:5432/mydatabasename?ssl=true&sslfactory=org.postgresql.ssl.NonValidatingFactory

1

이 이미지와 같은 문제가있었습니다.

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

몇 가지 해결책을 시도했습니다. 그러나 같은 프로젝트라도 다른 작업장에있을 때는 완전히 괜찮습니다. 추가 설정이 필요하지 않습니다. 그래서 우리는 그것이 환경 문제라고 생각했습니다. JDK 버전, IDE를 변경하려고 시도했지만 작동하지 않았습니다. 우리가 최고 답변을 시도 할 때까지 조사에 약 4 시간이 걸렸습니다. 해당 답변에 언급 된 오류를 찾지 못했지만 브라우저를 통해 Charles의 인증이있는 HTTP URL (잠금)에 대해 발견했습니다. 그런 다음 내 찰스가 항상 있다는 것을 깨달았습니다. 내가 그 기능을 끄면 제대로 작동합니다.

그래서 나는 당신의 사건에 도움이 될 수있는 나의 경험을 떠났습니다.


0

제 경우에는 Java 1.6에서 MacOs High Sierra를 실행하고 있습니다. cacert 파일은 Gabe Martin-Dempesy의 답변에서 위에서 언급 한 것과 다른 위치에 있습니다. cacert 파일은 이미 다른 위치 (/ Library / Internet Plug-Ins / JavaAppletPlugin.plugin / Contents / Home / lib / security / cacerts)에 연결되었습니다.

FireFox를 사용하여 해당 웹 사이트의 인증서를 "exportedCertFile.crt"라는 로컬 파일로 내보냈습니다. 거기서 keytool을 사용하여 인증서를 cacert 파일로 옮겼습니다. 문제가 해결되었습니다.

bash-3.2# cd /Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/lib/security/
bash-3.2# keytool -importcert -file ~/exportedCertFile.crt -alias example -keystore cacerts -storepass changeit

0

먼저 SSL 인증서를 다운로드하면 Java bin 경로로 이동하여 콘솔에서 아래 명령을 실행할 수 있습니다.

C:\java\JDK1.8.0_66-X64\bin>keytool -printcert -file C:\Users\lova\openapi.cer -keystore openapistore

-1

필자의 경우 키 저장소와 신뢰 저장소에 동일한 인증서가 있으므로 신뢰 저장소를 제거하는 데 도움이되었습니다. 인증서 사본이 여러 개인 경우 인증서 체인이 문제가 될 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.