ChatGPT解决这个技术问题 Extra ChatGPT

Java:sun.security.provider.certpath.SunCertPathBuilderException:无法找到请求目标的有效证书路径

我有一个类将从 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。对于可能处于类似情况的其他任何人,仅供参考。

C
Community

当您的服务器具有自签名证书时会出现问题。要解决此问题,您可以将此证书添加到 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) 为我工作
G
Gabe Martin-Dempesy

这是在 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 <(openssl s_client -connect example.com:443 -prexit 2>/dev/null) -out ~/example.crt - 什么是命令中的 example.crt 我需要提供一个 .pem 证书那在这里??
.crt 和 .pem 是相同文件格式的常用文件扩展名。如果您已经拥有该文件,只需运行第二个命令并将其传递给 -file 参数。
好东西。唯一的问题是:出于某种原因,我不得不使用最新的 openssl 1.0.Xx,旧的 9.X.Xx 无法正常工作。
这不适用于 SNI 端点。对于这种情况,您需要在获取证书时添加: -servername example.com
S
Stephan Oudmaijer

我对来自 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 文件。
N
Nayuki

使用 Firefox 导出 SSL 证书。您可以通过在浏览器中点击 URL 来导出它,然后选择导出证书的选项。假设证书文件名为 your.ssl.server.name.crt 转到 JRE_HOME/bin 或 JDK/JRE/bin 键入命令 keytool -keystore ..\lib\security\cacerts -import -alias your.ssl。 server.name -file .\relative-path-to-cert-file\your.ssl.server.name.crt 重新启动 Java 进程


如果要求输入密码,请使用默认的 cacerts 密钥库密码 changeit (stackoverflow.com/a/22782035/1304830)。还要确保以管理员身份运行 cmd。
b
bhdrk

@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 更改了他的证书并导致我的构建失败。这解决了我的问题
甲骨文应该首先提供类似的东西,或者从来没有每个人都创建过自己可怕的 SSL 解决方案。 SSL 证书处理应该是操作系统的工作。
谢谢@bhdrk。
非常感谢!我想做一些对我有帮助的编辑。 1.不要忘记从su启动时JAVA_HOME是不同的 2.在cacertspath = ${javahome}/lib/security/cacerts中,可能需要插入一个/jre/,即cacertspath =${javahome}/jre /lib/security/cacerts
N
Nishant

引自 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 使用服务器证书对服务器进行身份验证,并且需要确保 SSL 安全,如 RFC 2246 中所述。证书根本不是秘密:因此您的评论的其余部分没有意义。
a
arnonuem

这解决了我的问题,

我们需要将证书导入本地 java。如果没有,我们可以获得以下异常。

javax.net.ssl.SSLHandshakeException: 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.ssl.Alerts.getSSLException(Alerts.java:192)
        at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949)
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)

SSLPOKE 是一个工具,您可以在其中从本地计算机测试 https 连接。

测试连通性的命令:

"%JAVA_HOME%/bin/java" SSLPoke <hostname> 443
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(PKIXValidator.java:387)
        at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
        at sun.security.validator.Validator.validate(Validator.java:260)
        at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
        at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
        at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
        at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1496)
        at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
        at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1026)
        at sun.security.ssl.Handshaker.process_record(Handshaker.java:961)
        at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
        at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
        at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:747)
        at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:123)
        at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:138)
        at SSLPoke.main(SSLPoke.java:31)
    Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to 
    requested target
        at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
        at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
        at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
        at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)
        ... 15 more
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    

我这样做了,但不知何故它总是显示错误日志
J
Jonas Bergström

我能够让它只使用代码,即不需要使用 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-5s),之后每个连接只需要300-400 ms。
P
Parker

仅适用于 Windows,请执行以下步骤:

在 Chrome 中转到设置。在设置中单击显示高级设置。在 HTTPS/SSL 下单击管理证书。导出您的证书。在 Windows 搜索中(按键盘上的 windows 键)输入 java。选择(配置 Java)选项,这将打开 Java 控制面板 在 Java 控制面板中选择安全选项卡 选择管理证书 单击导入 在(用户)选项卡下选择,证书类型为(受信任的证书)单击导入按钮并浏览到下载的证书并导入它。


P
Parker

我的 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 测试来检查缺少哪个证书。找到适当的证书后,下载它并(如果服务器在您的控制之下)将其添加到证书包中。或者,您可以在本地导入缺少的证书。在服务器上解决此问题是该问题的更通用解决方案。


ssllabs.com/ssltest 是一个救星,只需将其与有效的证书验证进行比较。
D
Daniel De León

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

一种方法是在 keystore 文件中设置 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


V
VicXj

我遵循的简单步骤。

问题:我试图使用简单的 java 类(main 方法)连接到端点(https://%s.blob.core.windows.net)。

因此,在问题中,我遇到了上面提到的这个认证问题。

解决方案:

使用浏览器(chrome)获取证书。为此,请将您的端点 URL 粘贴到浏览器中并输入。现在你会看到一个锁图标,点击它-->证书-->详细信息-->复制到文件-->下载它。以管理员身份打开 cmd(我使用的是 Windows),然后导航到您下载 .cer 文件的目录。

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

现在使用以下命令

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

提供默认密码:changeit 信任此证书:是

你完成了。

谢谢!


g
gavenkoa

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

S
StaticNoiseLog

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

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


L
Lalaphoon

有像这张图片这样的问题。

https://i.stack.imgur.com/u1N1A.png

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

因此,我留下了可能对您的案例有所帮助的经验。


B
Brad Parks

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

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

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


I
Insoft

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

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


F
Frederic Leitenberger

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

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

r
raikumardipak
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.

P
Pradip Das

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

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

A
Amr Ibrahim

https://i.stack.imgur.com/RYLoe.png

这对我有用


如果浏览器也报错怎么办?
尝试安装证书
在我的情况下,浏览器没问题,但我仍然在 java 中遇到错误
B
Bastien Gallienne

如果在 maven 或带有 TestNG 的 maven 中出现此错误:

从目标网站下载证书并在您的机器上安装证书(使用上面建议的 keytool,或在 Windows 上)将以下内容添加到 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"

A
Alan Curtis

就我而言,我正在使用 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

L
Lova Chittumuri

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

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

S
Smart Coder

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


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

由于最初的问题是 - 如何忽略证书错误,这里是使用 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);
        //...
    }
}

D
Dorjee Dhondup

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

重新启动您的应用程序,证书错误应该会消失!


F
Fabien

这适用于您只需要安装 JDK 的任何操作系统:

从远程服务器下载证书:keytool -printcert -rfc -sslserver <您的远程服务器主机名> > /tmp/remorte-cert.crt 将证书导入您的 JDK 密钥库:keytool -importcert -file /tmp/remorte-cert。 crt -alias <远程服务器的别名> -storepass changeit -keystore "${JAVA_HOME}/lib/security/cacerts" -noprompt