当前位置: 首页 > 知识库问答 >
问题:

SSL证书验证:javax.net.ssl.SSLHandshakeException

刘琨
2023-03-14

我正在尝试通过泽西客户端调用HTTPS REST API。在开发过程中,我偶然发现了以下错误:

Exception in thread "main" com.sun.jersey.api.client.ClientHandlerException: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No name matching mvn.signify.abc.com found
    at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:149)
    at com.sun.jersey.api.client.Client.handle(Client.java:648)
    at com.sun.jersey.api.client.WebResource.handle(WebResource.java:670)
    at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74)
    at com.sun.jersey.api.client.WebResource$Builder.get(WebResource.java:503)
    at com.lftechnology.sbworkbench.utility.utils.PingFederateUtility.main(PingFederateUtility.java:32)
Caused by: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No name matching mvn.signify.abc.com found

所以我用谷歌搜索了一下,找到了大量的解决方案,实际上是有效的。

  1. 使用泽西客户端的HTTPS
  2. https://gist.github.com/outbounder/1069465
  3. 如何修复java.security.cert.证书异常:不存在主题替代名称错误?
  4. http://www.mkyong.com/webservices/jax-ws/java-security-cert-certificateexception-no-name-matching-localhost-found/
  5. http://java.globinch.com/enterprise-java/security/fix-java-security-certificate-exception-no-matching-localhost-found/

他们在不同的领域,但他们有一个共同的解决方案。

我目前正在开发环境中使用自行创建的自签名证书。因此必然会出现这个问题。

上述解决方案侧重于跳过/允许验证所有证书。

但是,当我将其移动到生产环境中时,我可以访问来自可靠来源的有效签名证书。

  1. 那么,这些解决方案在我进入生产阶段时有帮助吗

附笔

我使用的解决方案是,

try
{
    // Create a trust manager that does not validate certificate chains
    TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
        }
        public void checkClientTrusted(X509Certificate[] certs, String authType) {
        }
        public void checkServerTrusted(X509Certificate[] certs, String authType) {
        }
    }
    };

    // Install the all-trusting trust manager
    SSLContext sc = SSLContext.getInstance("SSL");
    sc.init(null, trustAllCerts, new java.security.SecureRandom());
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

    // Create all-trusting host name verifier
    HostnameVerifier allHostsValid = new HostnameVerifier() {
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    };

    // Install the all-trusting host verifier
    HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
} catch (NoSuchAlgorithmException e) {
    e.printStackTrace();
} catch (KeyManagementException e) {
    e.printStackTrace();
}

然后我与Jersey合作使其工作。它工作得很好。

那么,问题又来了。该解决方案在生产环境中使用可行吗?但是,您不想修改返回的实体,最好以只读模式获取实体。这将允许Hibernate丢弃关联的分离状态,脏检查机制使用该状态来检测实体状态修改。此外,在刷新期间跳过只读实体。

共有3个答案

杜凯
2023-03-14

创建自签名证书时,Java Keytool for Java version 1.7.0_60-b19存在标签软件错误。请参阅这些说明以获取参考。

https://www.sslshopper.com/article-how-to-create-a-self-signed-certificate-using-java-keytool.html

当它提示你“你的名字和姓氏是什么?”,您应该输入通用名称或(服务器的完全限定域名),而不是键入您的名称。

[root@localhost ~]# keytool -genkey -keyalg RSA -alias myalias -keystore keystore.jks -storepass XXXXXX -validity 360 -keysize 2048
What is your first and last name?
  [Unknown]:  Angus MacGyver
What is the name of your organizational unit?
  [Unknown]:  My Department
What is the name of your organization?
  [Unknown]:  My Company
What is the name of your City or Locality?
  [Unknown]:  My City
What is the name of your State or Province?
  [Unknown]:  My State
What is the two-letter country code for this unit?
  [Unknown]:  US
Is CN=Angus MacGyver, OU=My Department, O=My Company, L=My City, ST=My State, C=US correct?
  [no]:  yes
Enter key password for <selfsigned>
        (RETURN if same as keystore password):XXXXXX
Re-enter new password:XXXXXX

您可以通过调用以下命令来验证“CN”(公共名称)属性是否设置正确:

[root@localhost ~]# keytool -v -list -keystore keystore.jks

查找Java版本:

[root@localhost ~]# java -version
java version "1.7.0_60"
Java(TM) SE Runtime Environment (build 1.7.0_60-b19)
Java HotSpot(TM) Client VM (build 24.60-b09, mixed mode, sharing)
师曦
2023-03-14

@jww正确地回答了这个问题

跳过SSL验证可以吗?不,那是非常不负责任的。

但是,在某些情况下,您可能无法控制相关服务器以安装有效证书。如果服务器属于其他人,并且您信任该服务器,更好的解决方案是使用“白名单”仅为受信任的服务器验证证书,否则使用正常验证。

public static class WhitelistHostnameVerifier implements HostnameVerifier {
    private static final HostnameVerifier defaultHostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
    private Set<String> trustedHosts;

    public WhitelistHostnameVerifier(Set<String> trustedHosts) {
        this.trustedHosts = trustedHosts;
    }

    @Override
    public boolean verify(String hostname, SSLSession session) {
        if (trustedHosts.contains(hostname)) {
            return true;
        } else {
            return defaultHostnameVerifier.verify(hostname, session);
        }
    }
}

并安装一次:

HttpsURLConnection.setDefaultHostnameVerifier(
    new WhitelistHostnameVerifier(Sets.newHashSet("trustedhost.mydomain.com")));

如果你要禁用安全检查,不要在全球范围内这样做...

崔涵亮
2023-03-14

我目前在开发环境中使用自己创建的自签名证书。...javax.net.ssl.SSLHandshakeException:java.security.cert.证书异常:未找到名称匹配dev.ppc.lftechnology.com

自签名证书似乎不正确。

下面是我用来创建自签名证书和测试期间使用的证书请求的OpenSSL配置文件。另存为example com。形态。根据您的喜好更改DNS名称。您甚至可以放置本地主机。localdomain和127.0.0.1用于测试。

如果要创建自签名证书,请使用:

openssl req -config example-com.conf -new -x509 -newkey rsa:2048 \
    -nodes -keyout example-com.key.pem -days 365 -out example-com.cert.pem

如果要创建将由受信任机构签名的签名请求(CSR),请使用:

openssl req -config example-com.conf -new -newkey rsa:2048 \
    -nodes -keyout example-com.key.pem -days 365 -out example-com.req.pem

自签名证书和签名请求之间的区别在于-x509选项。存在-x509时,将创建自签名证书。没有-x509表示创建了请求。

如果您想打印自签名证书或请求以查看其中的实际内容,请使用:

openssl x509 -in example-com.cert.pem -text -noout
openssl req -in example-com.req.pem -text -noout

如果要测试服务器,请使用s\u客户端:

openssl s_client -connect <server>:<port> -CAfile <trust-anchor.pem>

上述命令应以类似于验证OK(0)的消息结束。如果您没有收到验证OK(0),请修复您的测试装置。一旦OpenSSL成功完成,这将成为您的基线。

[ req ]
default_bits        = 2048
default_keyfile     = server-key.pem
distinguished_name  = subject
req_extensions      = req_extensions
x509_extensions     = cert_extensions
string_mask         = utf8only

[ subject ]
countryName         = Country Name (2 letter code)
countryName_default     = US

stateOrProvinceName     = State or Province Name (full name)
stateOrProvinceName_default = NY

localityName            = Locality Name (eg, city)
localityName_default        = New York

organizationName         = Organization Name (eg, company)
organizationName_default    = Example, LLC

# Use a friendly name here. Its presented to the user.
#   The server's DNS name show up in Subject Alternate Names. Plus, 
#   DNS names here is deprecated by both IETF and CA/Browser Forums.
commonName          = Common Name (e.g. server FQDN or YOUR name)
commonName_default      = Example Company

emailAddress            = Email Address
emailAddress_default        = test@example.com

[ cert_extensions ]

subjectKeyIdentifier        = hash
authorityKeyIdentifier  = keyid,issuer

basicConstraints        = CA:FALSE
keyUsage            = digitalSignature, keyEncipherment
# extendedKeyUsage  = serverAuth
subjectAltName          = @alternate_names
nsComment           = "OpenSSL Generated Certificate"

[ req_extensions ]

subjectKeyIdentifier        = hash

basicConstraints        = CA:FALSE
keyUsage            = digitalSignature, keyEncipherment
# extendedKeyUsage  = serverAuth
subjectAltName          = @alternate_names
nsComment           = "OpenSSL Generated Certificate"

[ alternate_names ]

DNS.1       = example.com
DNS.2       = www.example.com
DNS.3       = mail.example.com
DNS.4       = ftp.example.com

# Add these if you need them. But usually you don't want them or
#   need them in production. You may need them for development.
# DNS.5       = localhost
# DNS.6       = localhost.localdomain
# DNS.7       = 127.0.0.1

可以跳过SSL验证吗?

不,那是非常不负责任的。如果你不打算正确使用PKIX,那为什么还要使用它呢?

我想到了:世界上最危险的代码:在非浏览器软件中验证SSL证书。

HostnameVerifier allHostsValid = new HostnameVerifier() {
    public boolean verify(String hostname, SSLSession session) {
        return true;
    }
};

最好将自签名证书加载到密钥库(或加载私有CA),然后将其传递给SSLContext。初始化。然后一切都按预期工作,不需要信任一切或从验证返回true。

Bruno和EJP对此有很多答案。

为开发和生产环境实现通用解决方案的另一种替代方法是什么?

使用格式良好的证书,该证书链接回受信任的根。

对于测试,您可以创建自签名证书。或者,创建一个证书请求,并让您的内部CA在私有PKI中对其进行签名。在这种情况下,您需要信任您的自签名证书或信任您的内部CA。

对于制作,您可以使用由CA Zoo的一个成员签名的证书,以便组织外的其他人也信任它。StartCom和CACert提供免费的1级证书。

1类证书通常经过域验证,不允许通配符。虽然类别1是免费发布的,但它们对撤销收取费用,因为这是成本所在。

如果你需要一张通配符,那么你通常会购买一张2级或更高的。

 类似资料:
  • 问题内容: 我正在尝试通过调用HTTPS REST API 。在开发过程中,我偶然发现以下错误: 因此,我在Google上搜索了一下,并找到了很多可行的解决方案。 使用Jersey客户端的HTTPS https://gist.github.com/outbounder/1069465 如何解决“ java.security.cert.CertificateException:不存在使用者替代名称”

  • 问题内容: 假设我编写了两个Java应用程序:并且它们被部署并在两个单独的服务器上运行(部署到和部署到),并且这两个应用程序需要通过SSL相互通信(双向)。我们还假设每个应用程序都有自己的SSL证书。 我(Java程序员)如何编码并验证彼此的SSL证书?每个CA是否都提供某种我可以使用的RESTful API ?Java是否有自己的证书验证API?我可以使用开放源代码的第三方JAR或服务吗? 当我

  • 假设我编写了两个Java应用程序:和,它们在两个独立的服务器上部署和运行(部署到和部署到

  • 当我想要在cPanel上安装证书时,我会看到以下错误: 错误证书验证失败! 已执行/usr/bin/openssl verify-capath/var/cpanel/ssl/installed/cabundles: stdin:CN=example.com 0深度查找时错误20:无法获取本地颁发者证书

  • 误差 PHP警告:stream_socket_client():SSL操作失败,代码为1。OpenSSL错误消息:错误:14090086:SSL例程:SSL3_GET_Server_Certifice:证书验证失败