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

Run*_*orn 8 java security ssl https

我试图通过调用HTTPS REST API Jersey Client.在开发过程中,我偶然发现了以下错误:

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
Run Code Online (Sandbox Code Playgroud)

所以我用Google搜索了一下,发现了大量的解决方案,实际上是有效的.

  1. 使用Jersey客户端的HTTPS
  2. https://gist.github.com/outbounder/1069465
  3. 如何修复"java.security.cert.CertificateException:没有主题替代名称出现"错误?
  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. 当我转向生产时,这些解决方案是否有任何帮助?
  2. 可以跳过SSL验证吗?
  3. 为开发和生产环境实现通用解决方案的另一种替代方法是什么?

PS

我使用的解决方案是,

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();
}
Run Code Online (Sandbox Code Playgroud)

然后我与之合作Jersey以使其发挥作用.它工作得很好.

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

jww*_*jww 13

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

看来自签名证书不正确.

下面是CONF我用来创建自签名证书和证书请求的OpenSSL 文件,以便在测试期间使用.保存为example-com.conf.[ alternate_names ]根据您的喜好更改DNS名称.你甚至可以把localhost,localhost.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
Run Code Online (Sandbox Code Playgroud)

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

openssl req -config example-com.conf -new -newkey rsa:2048 \
    -nodes -keyout example-com.key.pem -days 365 -out example-com.req.pem
Run Code Online (Sandbox Code Playgroud)

可以选择自签名证书和签名请求之间的区别-x509.随着-x509目前,创建一个自签名证书.缺少-x509意味着创建了请求.

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

openssl x509 -in example-com.cert.pem -text -noout
openssl req -in example-com.req.pem -text -noout
Run Code Online (Sandbox Code Playgroud)

如果要测试服务器,请使用s_client:

openssl s_client -connect <server>:<port> -CAfile <trust-anchor.pem>
Run Code Online (Sandbox Code Playgroud)

上面的命令应该以类似的消息结束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
Run Code Online (Sandbox Code Playgroud)

可以跳过SSL验证吗?

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

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


HostnameVerifier allHostsValid = new HostnameVerifier() {
    public boolean verify(String hostname, SSLSession session) {
        return true;
    }
};
Run Code Online (Sandbox Code Playgroud)

最好将自签名证书加载到密钥库(或加载您的私有CA),然后将其传递给SSLContext.init.然后一切都按预期工作,没有必要相信一切或true从中回来verify.

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


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

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

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

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

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

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


小智 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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

并安装一次:

HttpsURLConnection.setDefaultHostnameVerifier(
    new WhitelistHostnameVerifier(Sets.newHashSet("trustedhost.mydomain.com")));
Run Code Online (Sandbox Code Playgroud)

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