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

时间:2014-08-01 11:57:14

标签: java security ssl https

我试图通过Jersey Client调用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 using Jersey Client
  2. https://gist.github.com/outbounder/1069465
  3. How to fix the "java.security.cert.CertificateException: No subject alternative names present" error?
  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/
  6. 他们处于不同的领域,但他们有一个共同的解决方案来解决它。

    方案

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

    问题

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

    但是当我将其移至生产环境时,我可以从可信赖的来源访问有效签名证书。

    1. 当我转向生产时,这些解决方案是否有任何帮助?
    2. 跳过SSL验证是否可以?
    3. 实现通用解决方案的另一种替代方法是什么? 开发和生产环境?
    4. P.S

      我使用的解决方案是,

      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合作以使其有效。它工作得很好。

      所以,再次Question此解决方案是否适用于生产环境? 但是,您不希望修改返回的实体,以只读模式获取实体要好得多。这将允许Hibernate丢弃相关的分离状态,脏状态检查机制使用该分离状态来检测实体状态修改。更多,在刷新期间会跳过只读实体。

3 个答案:

答案 0 :(得分:13)

  

我目前正在使用自创的自签名证书   发展环境。 ... javax.net.ssl.SSLHandshakeException:   java.security.cert.CertificateException:没有名称匹配   dev.ppc.lftechnology.com发现

自签名证书似乎不正确。

下面是我用来创建自签名证书和证书请求的OpenSSL CONF文件,以便在测试期间使用。将其另存为example-com.conf。更改[ alternate_names ]下的DNS名称以符合您的口味。您甚至可以将localhostlocalhost.localdomain127.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_client

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

上述命令应该以类似于Verify OK (0)的消息结束。如果您没有收到Verify 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,那么为什么要使用它?

我想到了这一点:The Most Dangerous Code in the World: Validating SSL Certificates in Non-Browser Software


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

最好在密钥库中加载自签名证书(或加载私有CA),然后将其传递给SSLContext.init。然后一切都按预期工作,并且不需要信任所有内容或从true返回verify

布鲁诺和EJP有很多关于这个主题的答案。


  

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

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

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

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

第1类证书通常经过域验证,不允许使用通配符。虽然Class 1是免费发行的,但他们会收取撤销费用,因为这是成本所在。

如果您需要外卡,那么您通常会购买2级或更高级别。

答案 1 :(得分:6)

@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")));

如果您要禁用安全检查,请不要全局执行...

答案 2 :(得分:1)

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

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

当它提示您输入&#34;您的名字和姓氏是什么?&#34;而不是输入您的姓名时,您应输入公用名,或(服务器的完全限定域名)。< / p>

[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

您可以验证&#34; CN&#34;通过调用它来正确设置(通用名称)属性:

[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)