source

Java: sun.security.provider.certpath.SunCertPathBuilder예외: 요청된 대상에 대한 올바른 인증 경로를 찾을 수 없습니다.

goodcode 2022. 8. 28. 09:37
반응형

Java: sun.security.provider.certpath.SunCertPathBuilder예외: 요청된 대상에 대한 올바른 인증 경로를 찾을 수 없습니다.

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

서버에 자체 서명된 인증서가 있는 경우 문제가 발생합니다.이 문제를 해결하려면 이 인증서를 JVM의 신뢰할 수 있는 인증서 목록에 추가하십시오.

이 문서 작성자는 브라우저에서 인증서를 가져와 JVM의 cacerts 파일에 추가하는 방법을 설명합니다.편집할 수 있습니다.JAVA_HOME/jre/lib/security/cacerts with file file file 。-Djavax.net.ssl.trustStore파라미터를 지정합니다.JDK/JRE를 사용합니다.혼동의 원인이 되는 경우가 많기 때문입니다.

다음 항목도 참조하십시오.SSL 증명서 서버명은 어떻게 해결됩니까?/키툴을 사용하여 대체 이름을 추가할 수 있습니까?에 부딪히면java.security.cert.CertificateException: No name matching localhost found★★★★★★ 。

다음은 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

Symantec의 유효한 서명 와일드카드 증명서도 같은 문제가 있었습니다.

먼저 -Djavax.net.java=를 사용하여 Java 응용 프로그램을 실행해 보십시오.SSL을 사용하여 실제로 무슨 일이 일어나고 있는지 확인합니다.

중간 증명서수입하게 되어 증명서 체인이 파손되었습니다.

Symantec에서 누락된 중간 증명서를 다운로드했습니다(SSL 핸드쉐이크 로그에서 누락된 증명서에 대한 다운로드 링크를 확인할 수 있습니다.내 경우는 http://svrintl-g3-aia.verisign.com/SVRIntlG3.cer).

그리고 자바 키스토어에서 cert를 Import했습니다.중간 증명서를 Import한 후 와일드카드 ssl 증명서가 기능하기 시작했습니다.

keytool -import -keystore ../jre/lib/security/cacerts -trustcacerts -alias "VeriSign Class 3 International Server CA - G3" -file /pathto/SVRIntlG3.cer
  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 프로세스 재시작

@Gabe Martin-Dempesy의 대답이 도움이 되었다.그리고 거기에 관련된 작은 대본을 썼습니다.사용법은 매우 간단합니다.

호스트에서 인증서 설치:

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

이미 설치되어 있는 증명서를 삭제합니다.

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

java-cert-displaces 입니다.

#!/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;

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

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

증명서 검증은 SSL 보안의 매우 중요한 부분이지만 자세한 내용을 설명하기 위해 이 엔트리를 쓰는 것은 아닙니다.관심 있으시다면, 위키피디아를 읽어보시는 것부터 시작하세요.원하신다면 테스트 증명서를 가지고 호스트와 대화하는 간단한 방법을 보여드리기 위해 이 엔트리를 작성했습니다.

기본적으로 신뢰할 수 있는 인증서와 함께 KeyStore에 서버 인증서를 추가합니다.

거기에 있는 코드를 시험해 보세요.도움이 될 것 같다.

이것으로 내 문제는 해결되었다.

로컬 자바에 증명서를 Import해야 합니다.그렇지 않으면 아래 예외를 둘 수 있습니다.

javax.net.ssl.SSLHandshakeException: sun.security.validator.검증자예외: PKIX 경로를 빌드하지 못했습니다. sun.security.provider.certpath.SunCertPathBuilder예외: 요청된 대상에 대한 올바른 인증 경로를 찾을 수 없습니다.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.검증자예외: PKIX 경로 빌드 실패:sun.security.certpath 를 지정합니다.SunCertPathBuilder예외: 요청된 대상에 대한 올바른 인증 경로를 찾을 수 없습니다.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에 있습니다.X509 Trust Manager Impl.validate (X509 Trust Manager Impl.java:324)sun.security.ssl에 있습니다.X509 Trust Manager Impl.checkTrusted(X509TrustManagerImpl.java:229)
sun.security.ssl에 있습니다.X509 Trust Manager Impl.check Server Trusted (X509 Trust Manager Impl.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에 있습니다.SSL Socket Impl.performInitialHandshake(SSLSocketImpl.java:1375)sun.security.ssl에 있습니다.SSL Socket Impl.writeRecord(SSLSocketImpl.java:747)sun.security.ssl에 있습니다.AppOutputStream.write(AppOutputStream).자바:123)sun.security.ssl에 있습니다.AppOutputStream.write(AppOutputStream).Java: 개요)SSLPoke.main(SSLPoke.java:31)에서원인: sun.security.provider.certpath.SunCertPathBuilder예외: 유효한 인증 경로를 찾을 수 없습니다.요구 대상sun.security.certpath에 있습니다.SunCertPathBuilder.빌드(SunCertPathBuilder.java:141)sun.security.certpath에 있습니다.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)java.security.cert로 이동합니다.Cert Path Builder.빌드(Cert Path Builder.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>

기본 비밀번호는 "Enter keystore password:"로 입력하라는 메시지가 먼저 표시되고 마지막으로 "Trust this certificate?"라는 메시지가 표시됩니다.[no]:, "yes"를 입력하여 인증서를 키 저장소에 추가합니다.

검증:

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

키툴을 사용할 필요가 없는 코드만으로 조작할 수 있었습니다.

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;
        }
    }
}

Windows 의 경우만, 다음의 순서에 따릅니다.

  1. Chrome에서 설정으로 이동합니다.
  2. 설정에서 고급 설정 표시를 클릭합니다.
  3. HTTPS/SSL에서 인증서 관리를 클릭합니다.
  4. 증명서를 내보냅니다.
  5. Windows 검색(키보드에서 Windows 키 누르기)에서 java를 입력합니다.
  6. Java 제어판을 여는 (Java 구성) 옵션을 선택합니다.
  7. Java 제어판에서 보안 탭을 선택합니다.
  8. 인증서 관리 선택
  9. [ Import ]을 클릭합니다.
  10. (사용자) 탭에서 선택한 인증서 유형(신뢰할 수 있는 인증서)
  11. [ Import ]버튼을 클릭하여 다운로드한 증명서를 참조하여 Import합니다.

Apache 2.4 인스턴스(Comodo 와일드카드 증명서 사용)에서 이 오류의 원인은 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

이 경우 중간 증명서가 누락되어 "Unable to find valid certification path to requested target" 메시지가 생성됩니다.서버에 대한 SSL Labs 테스트를 사용하여 누락된 인증서를 확인할 수 있습니다.적절한 증명서를 찾으면 다운로드하여 (서버가 사용자의 관리 하에 있는 경우) 증명서 번들에 추가합니다.또는 누락된 인증서를 로컬로 가져올 수 있습니다.이 문제를 서버에서 해결하는 것이 이 문제에 대한 보다 일반적인 해결책입니다.

이 문제를 해결할 수 있는 많은 방법이 있다...

한 가지 방법은 KeyStore 파일에 TrustStore 증명서를 설정하여 응용 프로그램 경로에 배치하고 메인 방식으로 다음 시스템 속성을 설정하는 것입니다.

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

다른 방법은 keystore를 프로젝트 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://stackoverflow.com/a/59056537/980442


파일을 ..crt다음과 같은 방법으로 파일을 작성합니다.

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

Debian 및 사전 패키지 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

내가 따라한 간단한 단계.

문제:단순한 Java 클래스(메인 메서드)를 사용하여 엔드포인트(s.blob.core.windows.net)에 접속하려고 했습니다.

그래서 저는 질문에서 위와 같은 인증 문제를 받고 있었습니다.

솔루션:

  1. 브라우저(크롬)를 사용하여 인증서를 가져옵니다.이를 수행하려면 브라우저에 엔드포인트 URL을 붙여넣고 다음과 같이 입력합니다.잠금 아이콘이 나타나면 해당 아이콘을 클릭합니다. -- > 증명서 -- > 상세 -- > 파일에 복사 -- > 다운로드하십시오.

  2. cmd(Windows 사용 중)를 admin으로 열고 .cer 파일을 다운로드한 디렉토리로 이동합니다.

3. (옵션)같은 시스템에서 여러 JDK를 사용하는 경우 애플리케이션에서 사용하는 것과 동일한 JDK 버전을 변경하십시오.K 버전을 변경합니다.

  1. 다음 명령을 사용합니다.

keytool -import -alias mycertificate -keystore "C:\Program Files\Java\jdk-11.0.5\lib\security\cacerts" - file myurlcrt.cer

  1. 기본 비밀번호 지정: changeit

  2. 이 증명서 신뢰: 예

그리고 넌 끝났어.

감사합니다!

업데이트: 재부팅이 도움이 된 것은 우연의 일치입니다(예상합니다만, 만세).문제의 진짜 원인은 다음과 같습니다.Gradle이 특정 키스토어를 사용하도록 지시된 경우 해당 키스토어에는 모든 공식 루트 증명서도 포함되어 있어야 합니다.그렇지 않으면 일반 저장소에서 라이브러리에 액세스할 수 없습니다.내가 해야 할 일은 이것이었다.

자기 서명 증명서를 Import 합니다.

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

그래들 데몬도 방해했나 봐도망가는 데몬을 다 죽일 가치가 있을 거야./gradlew --status상황이 암담해지기 시작하면요

최초 투고:

아무도 믿지 않을 거야, 나도 알아.그래도 다른 모든 것이 실패하더라도 시도해 보십시오. Mac을 재부팅한 후 문제가 사라졌습니다.으르렁.

배경: ./gradlew jar에서 "요청된 대상에 대한 유효한 인증 경로를 찾을 수 없습니다"라는 메시지가 계속 표시됨

브라우저에서 저장한 자기 서명 증명서가 privateKeystore.jks에 Import되어 있습니다.그런 다음 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

앞서 설명한 바와 같이 이 기능은 재부팅 후에만 작동합니다.

이 이미지처럼 문제가 있었다.

여기에 이미지 설명 입력

몇 가지 해결책을 시도했다.하지만 같은 프로젝트라도 다른 사람의 작업장에 있을 때는 전혀 문제가 없다는 것을 알게 되었습니다.추가 설정은 필요 없습니다.그래서 우리는 그것이 환경적인 문제라고 추측했다.JDK 버전, IDE를 변경하려고 했지만 잘 되지 않았습니다.조사하는데 4시간 정도 걸렸어요 최고 등급의 답변을 시도하기까지요저는 그 답변에서 언급된 오류를 발견하지 못했지만, 제 브라우저를 통해 HTTP URL(잠금)에 대해 Charles의 인증이 있다는 것을 알게 되었습니다.그때 찰스가 항상 켜져 있다는 걸 깨달았어요.내가 그걸 꺼놓기만 하면 다 괜찮아.

그래서 저는 당신의 사건에 도움이 될 수 있는 제 경험을 남겼습니다.

이는 SHA2를 사용하여 서명된 Java 7에서 GoDaddy 인증서를 사용하는 경우에도 발생할 수 있습니다.

Chrome 및 기타 모든 브라우저는 SHA1을 사용하여 서명된 SSL 인증서를 보안 수준이 낮기 때문에 권장하지 않습니다.

문제에 대한 자세한 내용은 여기를 참조해 주세요.또, 필요에 따라서, 서버상에서 문제를 해결하는 방법도 참조해 주세요.

AVG 버전 18.1.3044(Windows 10 탑재)는 로컬 Spring 애플리케이션과 간섭합니다.

해결책: "Web and e-메일"이라는 AVG 섹션에 입력하고 "전자 메일 보호"를 비활성화합니다.사이트가 안전하지 않은 경우 AVG는 인증서를 차단합니다.

증명서 오류에 대해서도 같은 문제가 있었습니다.그 이유는 SNI 때문입니다.사용하고 있는http 클라이언트에 SNI가 실장되어 있지 않습니다.버전 업데이트를 통해

   <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.3.6</version>
    </dependency>
Download the certificate from Nexus3 Browser (click on the lock-pad for View Site Information in case of Edge broser)
Click on Connection is secure
Click on the certificate details
Click on Copy To file (it opens up export certificate wizard)
Choose Base-64 encoding
Browse and select a download location and file-name (let’s say mycert)
Open cmd
Goto the download location and execute the below command
keytool -import -alias mycert -keystore  "<<your-JAVA_HOME-directory>>\jre\lib\security\cacerts" -file mycert.cer
Restart the machine
Execute maven build again.

두 가지 옵션이 있습니다. 소프트웨어가 실행되는 각 jvm에 대해 자체 서명된 인증서를 Java의 키 저장소로 가져오거나 검증되지 않은 ssl 팩토리를 사용해 보십시오.

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

https://176.66.3.69:6443/유효한 증명서가 있는 것을 확인합니다.브라우저에서 작동한다면 먼저 브라우저를 통해 확인할 수 있습니다.

그것은 나에게 효과가 있다.

저는 Java 1.6을 탑재한 MacOs High Sierra를 실행하고 있습니다.cacert 파일은 Gabe Martin-Dempesy의 답변에서 언급된 것과 다른 위치에 있습니다.cacert 파일은 다른 위치(/Library/인터넷 플러그인/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

먼저 ssl 증명서를 다운로드한 후 java bin path로 이동하여 콘솔에서 다음 명령을 수행합니다.

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

제 경우 keystore와 truststore 모두 동일한 증명서를 가지고 있기 때문에 truststore를 삭제하는 것이 도움이 되었습니다.인증서 사본이 여러 개 있는 경우 인증서 체인이 문제가 될 수 있습니다.

당초의 질문은, 「증명서 에러를 무시하는 방법」이었습니다만, Spring Boot 및 Rest Template 를 사용하고 있는 유저를 위한 솔루션을 소개합니다.

@Service
public class SomeService {

    private final RestTemplate restTemplate;

    private final ObjectMapper objectMapper;    

    private static HttpComponentsClientHttpRequestFactory createRequestFactory() {
        try {
            SSLContextBuilder sslContext = new SSLContextBuilder();
            sslContext.loadTrustMaterial(null, new TrustAllStrategy());
            CloseableHttpClient client = HttpClients.custom().setSSLContext(sslContext.build()).setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).build();
            HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
            requestFactory.setHttpClient(client);
            return requestFactory;
        } catch (KeyManagementException | KeyStoreException | NoSuchAlgorithmException var3) {
            throw new IllegalStateException("Couldn't create HTTP Request factory ignore SSL cert validity: ", var3);
        }
    }

    @Autowired
    public SomeService(RestTemplate restTemplate, ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
        this.dimetorURL = dimetorURL;
        restTemplate.setRequestFactory(createRequestFactory());
    }


    public ResponseEntity<ResponseObject> sendRequest(RequestObject requestObject) {
        //...
        return restTemplate.exchange(url, HttpMethod.GET, ResponseObject.class);
        //...
    }
}

이 에러가 Maven 또는 TestNG에서 발생하는 경우:

  1. 대상 웹사이트에서 증명서를 다운로드하여 머신에 증명서를 설치합니다(위에서 제시한 키툴을 사용하거나 Windows에서).
  2. maven 인수(명령줄 및/또는 IDE)에 -Djavax.net.ssl.trustStore=C:\Users\me.keystore -Djavax.net.ssl.trustStorePassword=X 여기서 X는 키툴 스텝에서 사용한 패스워드입니다.

메모: C:\Users\me.또, 사용의 머신에 맞추어 keystore를 설정할 필요가 있습니다.예:

mvn -ea -Dtestng.dtd.http=true  -Djavax.net.ssl.trustStore=C:\Users\me\.keystore -Djavax.net.ssl.trustStorePassword=X -Dmaven.wagon.http.ssl.insecure=true -Dmaven.wagon.http.ssl.allowall=true -Dmaven.wagon.http.ssl.ignore.validity.dates=true -Dcucumber.features=src/test/resources -Dcucumber.glue=com.myapp -Dcucumber.filter.tags="@MY_TEST"

이것이 MacOS에서 작동한 것입니다.server-name 및 server-port를 자신의 것으로 바꿉니다.

단말기에서 다음 두 가지 명령을 실행합니다.

원격 서버에서 인증서 다운로드

openssl x509 -in <(openssl s_client -connect server-name:server-port -prexit 2>/dev/null) -out ~/server-name.crt

Java 키스토어로 인증서 가져오기

sudo keytool -importcert -file ~/server-name.crt -alias server-name -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit

애플리케이션을 재기동하면, 증명서의 에러가 해소됩니다.

언급URL : https://stackoverflow.com/questions/6908948/java-sun-security-provider-certpath-suncertpathbuilderexception-unable-to-find

반응형