【问题标题】:Java: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested targetJava:sun.security.provider.certpath.SunCertPathBuilderException:无法找到请求目标的有效证书路径
【发布时间】:2011-10-18 01:07:23
【问题描述】:

我有一个类将从 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

【问题讨论】:

  • 有一次我遇到这个错误并联系了我们的安全团队,结果发现我必须修补我们正在使用的 JAR,因为我们的团队使用的是公司提供的过时的 JAR。对于可能处于类似情况的其他人,仅供参考。

标签: java ssl https ssl-certificate


【解决方案1】:

当您的服务器具有自签名证书时会出现问题。要解决此问题,您可以将此证书添加到 JVM 的受信任证书列表中。

In this article 作者描述了如何从浏览器获取证书并将其添加到 JVM 的 cacerts 文件中。您可以编辑JAVA_HOME/jre/lib/security/cacerts 文件或使用-Djavax.net.ssl.trustStore 参数运行您的应用程序。验证您也在使用哪个 JDK/JRE,因为这通常会造成混淆。

另请参阅:How are SSL certificate server names resolved/Can I add alternative names using keytool? 如果遇到java.security.cert.CertificateException: No name matching localhost found 异常。

【讨论】:

  • 这对我不起作用。我已经安装了根证书和链证书,但 Tomcat-7 仍然报告由“无法找到请求目标的有效证书路径”引起的验证器异常,有什么方法可以调试吗?
  • 由不受信任的其他人签署的证书也会出现问题。
  • 太棒了!有用!只是不要忘记你可以同时拥有 jre 和 jdk,并且它们的 cacerts 都必须更新
  • 在我的例子中,根 CA 在那里,但下一个 CA 不存在。添加下一个 CA 可以解决问题 - 谢谢。
  • 就我而言,我使用的是 Netbeans + Apache Tomcat(集成),因此,将 .cer 添加到 Jdk/jre 上的信任存储“cacerts”(C:\Program Files\Java\jdk1 .8.0_152\jre\lib\security) 和 Jre (C:\Program Files\Java\jre1.8.0_91\lib\security) 对我有用
【解决方案2】:

这就是在 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

【讨论】:

  • 为什么对我有用?您需要提供解释。
  • openssl x509 -in /dev/null) -out ~/example.crt - 我的命令中的 example.crt 是什么我需要在这里提供一个 .pem 证书??
  • .crt 和 .pem 是相同文件格式的常用文件扩展名。如果您已经拥有该文件,只需运行第二个命令并将其传递给 -file 参数。
  • 好东西。唯一的问题是:出于某种原因,我不得不使用最新的 openssl 1.0.Xx,旧的 9.X.Xx 无法正常工作。
  • 这不适用于 SNI 端点。对于这种情况,您需要在获取证书时添加:-servername example.com
【解决方案3】:

我在使用来自 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

【讨论】:

  • 是这样的:
  • 为避免混淆,使用调试参数运行 java(或 jcurl)以在日志中查看远程“证书链”,然后 grep 显式传递(而不是默认)信任库中的“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
  • 我也遇到了同样的问题,这非常有用,但在我的情况下,您只需将服务器证书添加到 JDK 版本的 cacerts 文件中
  • 请记住,还有一个名为 portecle 的工具可以打开 cacert 文件(证书存储)并轻松导入证书。之后记得保存 cacert 文件。
【解决方案4】:
  1. 使用 Firefox 导出 SSL 证书。您可以通过在浏览器中点击 URL 来导出它,然后选择导出证书的选项。假设证书文件名为 your.ssl.server.name.crt
  2. 转到您的JRE_HOME/binJDK/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进程

【讨论】:

【解决方案5】:

@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)。就是这样。
  • 效果很好。我在连接到外部 API 的 Jenkins 服务器上遇到错误,该 API 更改了他的证书并导致我的构建失败。这解决了我的问题
  • Oracle 应该一开始就提供这样的东西,或者从来没有每个人都创建过自己可怕的 SSL 解决方案。 SSL 证书处理应该是操作系统的工作。
  • 谢谢@bhdrk。
  • 非常感谢!我想做一些对我有帮助的编辑。 1.不要忘记从su开始时JAVA_HOME是不同的 2.在cacertspath = ${javahome}/lib/security/cacerts中,可能需要插入一个/jre/,即cacertspath =${javahome}/jre /lib/security/cacerts
【解决方案6】:

引用No more 'unable to find valid certification path to requested target'

尝试使用 JSSE 打开与主机的 SSL 连接时。这通常意味着服务器正在使用测试证书(可能使用 keytool 生成),而不是来自知名商业证书颁发机构(如 Verisign 或 GoDaddy)的证书。在这种情况下,Web 浏览器会显示警告对话框,但由于 JSSE 无法假定存在交互式用户,因此默认情况下只会抛出异常。

证书验证是 SSL 安全的一个非常重要的部分,但我写这篇文章并不是为了解释细节。如果您有兴趣,可以从阅读 Wikipedia 简介开始。我写这篇文章是为了展示一种使用测试证书与主机对话的简单方法,如果你真的想的话。

基本上,您希望将服务器的证书与您信任的证书一起添加到 KeyStore

试试那里提供的代码。这可能会有所帮助。

【讨论】:

  • 关于“证书验证是 SSL 安全的一个非常重要的部分”的部分不一定正确。 SSL 为您提供两个保证:(1) 您的通信是私密的,以及 (2) 您正在与 NSA 已知的服务器交谈。(:-) 有时您只关心对话的隐私,然后自签名证书很好。见social-biz.org/2011/10/16/the-anti-ssl-conspiracy
  • @AgilePro SSL 为您提供四个保证:身份验证、隐私、完整性和授权的可能性。它确实向您保证您正在与 NSA 已知的服务器通信。只关心隐私而不进行身份验证是自相矛盾的。
  • @EJP 同意,如果您使用客户端证书,您可以获得身份验证,我想授权的可能性......但大多数用途不是使用客户端证书。您认为“自签名”证书和来自签名机构的证书之间的区别是什么?签名权限是否赋予“完整性”。我关于 NSA 的笑话是,所有签署机构都不能积极保证独立于一切。真的不是那种偏执狂,但关键是你的证书只有签名机构可以做到的秘密。自签名可以更加保密。
  • @AgilePro 使用 server 证书对服务器进行身份验证,并且是 必需 以确保 SSL 安全,如 RFC 2246 中所述。证书不是机密的完全没有:因此您的其余评论毫无意义。
【解决方案7】:

这解决了我的问题,

我们需要将证书导入本地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 是默认密码。最后提示“信任此证书?[否]:”,提供“是”以将证书添加到密钥库。

验证:

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

【讨论】:

  • 我这样做了,但不知何故它总是显示错误日志
【解决方案8】:

我只能使用代码让它工作,即无需使用 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;
        }
    }
}

【讨论】:

  • 顺便说一句,我正在使用 httpasyncclient:4.0.1
  • 我需要类似的东西,@JonasBergström,您使用 SSLContext 的解决方案很有帮助。
  • 请注意,此解决方案是不安全的。
  • 谢谢乔纳斯,您的解决方案确实解决了问题。但是我发现创建第一个连接需要很长时间(3-5秒),之后每个连接只需要300-400毫秒。
【解决方案9】:

仅适用于 Windows,请按以下步骤操作:

  1. 在 Chrome 中转到设置。
  2. 在设置中单击显示高级设置。
  3. 在 HTTPS/SSL 下单击管理证书。
  4. 导出您的证书。
  5. 在 Windows 搜索中(按键盘上的 windows 键)键入 java。
  6. 选择将打开 Java 控制面板的(配置 Java)选项
  7. 在 Java 控制面板中选择安全选项卡
  8. 选择管理证书
  9. 点击导入
  10. 在(用户)选项卡下选中,证书类型为(可信证书)
  11. 点击导入按钮,浏览下载的证书并导入。

【讨论】:

    【解决方案10】:

    我的 Apache 2.4 实例(使用 Comodo 通配符证书)上出现此错误的原因是 SHA-1 签名根证书的路径不完整。颁发的证书中有多个链,指向 SHA-1 根证书的链缺少 intermediate certificate。现代浏览器知道如何处理这个问题,但 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 对服务器进行测试来检查缺少哪个证书。找到适当的证书后,下载它并(如果服务器在您的控制之下)将其添加到证书包中。或者,您可以在本地导入缺少的证书。在服务器上解决此问题是解决该问题的更通用方法。

    【讨论】:

    【解决方案11】:

    有很多方法可以解决这个问题...

    一种方法是在密钥库文件中设置 TrustStore 证书并将其放在应用程序的路径中,并在 main 方法中设置这些系统属性:

    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://stackoverflow.com/a/59056537/980442


    我以这种方式从证书颁发机构 CA .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

    【讨论】:

      【解决方案12】:

      对于那些喜欢 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
      

      【讨论】:

        【解决方案13】:

        我遵循的简单步骤。

        问题:我试图使用一个简单的 java 类(main方法)。

        所以我在问题中遇到了上面提到的这个认证问题。

        解决方案:

        1. 使用浏览器(chrome)获取证书。为此,请将您的端点 URL 粘贴到浏览器中并输入。现在你会看到一个锁图标,点击它-->证书-->详细信息-->复制到文件-->下载它。

        2. 以管理员身份打开 cmd(我使用的是 windows),然后导航到您下载 .cer 文件的目录。

        3.(可选)如果您在同一台机器上使用多个 JDK,请将您的 JDK 版本更改为与您在应用程序中使用的相同。

        1. 现在使用以下命令

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

        1. 提供默认密码:changeit

        2. 相信这个证书:是的

        你就完成了。

        谢谢!

        【讨论】:

          【解决方案14】:

          更新:重启帮助是巧合(我希望如此,万岁!)。问题的真正原因是:当 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 重新启动之后,问题就消失了。咕噜。

          背景: ./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
          

          如前所述,这仅在重新启动后才有效。

          【讨论】:

            【解决方案15】:

            遇到了像这张图片这样的问题。

            尝试了一些解决方案。 但是发现即使是同一个项目,在别人工作的地方也完全没问题。无需额外设置。所以我们猜测这是一个环境问题。我们尝试更改 JDK 版本、IDE 但没有奏效。调查花了大约 4 个小时,直到我们尝试了最受好评的答案。我没有找到该答案中提到的错误,但我通过浏览器发现有关 HTTP URL(锁定)的信息有 Charles 的认证。然后我意识到我的查尔斯一直在工作。只要我关闭它,它就可以正常工作。

            所以我留下了可能对你的案子有帮助的经验。

            【讨论】:

              【解决方案16】:

              这也可能是由使用 SHA2 签名的带有 Java 7 的 GoDaddy 证书引起的。

              Chrome 和所有其他浏览器开始弃用使用 SHA1 签名的 SSL 证书,因为它不那么安全。

              更多信息on the issue can be found here,以及如果您现在需要如何在您的服务器上解决它。

              【讨论】:

                【解决方案17】:

                AVG 版本 18.1.3044(使用 Windows 10)干扰了我的本地 Spring 应用程序。

                解决方案: 进入 AVG 部分名为“Web 和电子邮件”并禁用“电子邮件保护”。 如果站点不安全,AVG 会阻止证书。

                【讨论】:

                  【解决方案18】:

                  我遇到了同样的证书错误问题,这是因为 SNI:我使用的 http 客户端没有实现 SNI。所以版本更新完成了这项工作

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

                  【讨论】:

                    【解决方案19】:

                    您有两个选择,将自签名证书导入到 java 的密钥库中,用于软件将在其上运行的每个 jvm 或尝试非验证 ssl 工厂:

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

                    【讨论】:

                      【解决方案20】:

                      确保https://176.66.3.69:6443/ 具有有效的证书。 您可以先通过浏览器检查它 如果它在浏览器中运行,它将在 java 中运行。

                      这对我有用

                      【讨论】:

                      • 如果浏览器也报错怎么办?
                      • 尝试安装证书
                      • 在我的情况下浏览器没问题,但我仍然在 java 中遇到错误
                      【解决方案21】:

                      在我的例子中,我使用 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
                      

                      【讨论】:

                        【解决方案22】:

                        首先下载ssl证书然后你可以去你的java bin路径在控制台中执行以下命令。

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

                        【讨论】:

                          【解决方案23】:

                          在我的情况下,我的密钥库和信任库都具有相同的证书,因此删除信任库会有所帮助。如果您有多个证书副本,有时证书链可能会成为问题。

                          【讨论】:

                          • 你是说你可以完全删除信任库,甚至不必处理证书?如果是这样,我很想知道,因为这些证书问题只会窃取我的生产力并浪费我无数小时的时间。
                          • 如果你有密钥库,那么可能是的。您需要在其中之一拥有证书。
                          【解决方案24】:

                          原来的问题是 - 如何忽略证书错误,这里是使用 SpringBoot 和 RestTemplate 的解决方案

                          @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);
                                  //...
                              }
                          }
                          

                          【讨论】:

                            【解决方案25】:

                            如果在 maven 中出现此错误,或者在使用 TestNG 的 maven 中出现此错误:

                            1. 从目标网站下载证书并在您的机器上安装证书(使用上面建议的 keytool,或在 Windows 上)
                            2. 将以下内容添加到 maven 参数(命令行和/或 IDE): -Djavax.net.ssl.trustStore=C:\Users\me.keystore -Djavax.net.ssl.trustStorePassword=X 其中 X 是您在 keytool 步骤中使用的密码。

                            注意: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"
                            

                            【讨论】:

                              【解决方案26】:
                              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.
                              

                              【讨论】:

                                猜你喜欢
                                • 2020-11-11
                                • 2020-09-14
                                • 1970-01-01
                                • 1970-01-01
                                • 2023-01-03
                                相关资源
                                最近更新 更多