java - 当我尝试执行 POST 时与 Java 握手失败

标签 java post ssl jersey-client

我尝试联系 *** 并使用 POST 发送一些数据。

我使用已导入到我的 Eclipse 项目中的 jersey-bundle-1.18.jar。这是我的代码:

    Client client = Client.create();
    WebResource webResource = client.resource("https://somesite.com");
    MultivaluedMap<String, String> map = new MultivaluedMapImpl();
    map.putSingle("key_name", API_KEY_NAME);
    map.putSingle("key_value", API_KEY_VALUE);
    map.putSingle("message", "Test");
    map.putSingle("extension", "+0012345678");
    ClientResponse response = webResource.type("application/x-www-form-urlencoded")
                 .post(ClientResponse.class, map); // throws exception here
    return response.toString();

当我运行我的代码时,我得到 javax.net.ssl.SSLHandshakeException。该站点使用的证书来自 StartCom,根据 this poster 的说法,我认为这个 CA 不在 Java 的默认信任库中,至少在 Java 6 中是这样

我使用 JVM 标志 -Djavax.net.debug=all 运行我的程序,这就是我得到的:

trigger seeding of SecureRandom
done seeding SecureRandom
Ignoring unavailable cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA256
Ignoring unavailable cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
Ignoring unavailable cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA
Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
Ignoring unavailable cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA
Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_128_CBC_SHA256
Allow unsafe renegotiation: false
Allow legacy hello messages: true
Is initial handshake: true
Is secure renegotiation: false
main, setSoTimeout(0) called
%% No cached client session
*** ClientHello, TLSv1
RandomCookie:  GMT: 1391505439 bytes = { 186, 52, 225, 5, 67, 137, 170, 128, 220, 41, 178, 86, 199, 17, 150, 190, 23, 47, 217, 126, 162, 34, 68, 40, 216, 221, 193, 108 }
Session ID:  {}
Cipher Suites: [TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA, SSL_RSA_WITH_RC4_128_SHA, TLS_ECDH_ECDSA_WITH_RC4_128_SHA, TLS_ECDH_RSA_WITH_RC4_128_SHA, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_RC4_128_MD5, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
Compression Methods:  { 0 }
Extension elliptic_curves, curve names: {secp256r1, sect163k1, sect163r2, secp192r1, secp224r1, sect233k1, sect233r1, sect283k1, sect283r1, secp384r1, sect409k1, sect409r1, secp521r1, sect571k1, sect571r1, secp160k1, secp160r1, secp160r2, sect163r1, secp192k1, sect193r1, sect193r2, secp224k1, sect239k1, secp256k1}
Extension ec_point_formats, formats: [uncompressed]
Extension server_name, server_name: [host_name: ***]
***
[write] MD5 and SHA1 hashes:  len = 176
0000: 01 00 00 AC 03 01 53 F1   B0 1F BA 34 E1 05 43 89  ......S....4..C.
0010: AA 80 DC 29 B2 56 C7 11   96 BE 17 2F D9 7E A2 22  ...).V...../..."
0020: 44 28 D8 DD C1 6C 00 00   2A C0 09 C0 13 00 2F C0  D(...l..*...../.
0030: 04 C0 0E 00 33 00 32 C0   07 C0 11 00 05 C0 02 C0  ....3.2.........
0040: 0C C0 08 C0 12 00 0A C0   03 C0 0D 00 16 00 13 00  ................
0050: 04 00 FF 01 00 00 59 00   0A 00 34 00 32 00 17 00  ......Y...4.2...
0060: 01 00 03 00 13 00 15 00   06 00 07 00 09 00 0A 00  ................
0070: 18 00 0B 00 0C 00 19 00   0D 00 0E 00 0F 00 10 00  ................
0080: 11 00 02 00 12 00 04 00   05 00 14 00 08 00 16 00  ................
main, WRITE: TLSv1 Handshake, length = 176
[Raw write]: length = 181
0000: 16 03 01 00 B0 01 00 00   AC 03 01 53 F1 B0 1F BA  ...........S....
0010: 34 E1 05 43 89 AA 80 DC   29 B2 56 C7 11 96 BE 17  4..C....).V.....
0020: 2F D9 7E A2 22 44 28 D8   DD C1 6C 00 00 2A C0 09  /..."D(...l..*..
0030: C0 13 00 2F C0 04 C0 0E   00 33 00 32 C0 07 C0 11  .../.....3.2....
0040: 00 05 C0 02 C0 0C C0 08   C0 12 00 0A C0 03 C0 0D  ................
0050: 00 16 00 13 00 04 00 FF   01 00 00 59 00 0A 00 34  ...........Y...4
0060: 00 32 00 17 00 01 00 03   00 13 00 15 00 06 00 07  .2..............
0070: 00 09 00 0A 00 18 00 0B   00 0C 00 19 00 0D 00 0E  ................
0080: 00 0F 00 10 00 11 00 02   00 12 00 04 00 05 00 14  ................
0090: 00 08 00 16 00 0B 00 02   01 00 00 00 00 17 00 15  ................
[Raw read]: length = 5
0000: 15 03 01 00 02                                     .....
[Raw read]: length = 2
0000: 02 28                                              .(
main, READ: TLSv1 Alert, length = 2
main, RECV TLSv1 ALERT:  fatal, handshake_failure
main, called closeSocket()
main, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
main, called close()
main, called closeInternal(true)
Exception in thread "main" com.sun.jersey.api.client.ClientHandlerException: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure

出了什么问题,我该如何让它发挥作用?

编辑:如下所述,我下载了 Java 加密扩展 (JCE) 无限强度管辖策略文件,但对于 Java 7,因为这是我正在使用的 Java 版本,并将 jar 文件复制到/lib/security按照说明。

我再次运行该程序,并卡在了另一个异常处。我从 Eclipse 控制台复制了几行:

%% Invalidated: [Session-1, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA] main, SEND TLSv1 ALERT: fatal, description = certificate_unknown main, WRITE: TLSv1 Alert, length = 2 [Raw write]: length = 7 0000: 15 03 01 00 02 02 2E ....... main, called closeSocket() main, handling exception: 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

这一次,似乎 Java 信任库中的 StartCom 证书终于不见了。我确信有可能克服这个问题,但由于我考虑将我的代码部署到一个可供其他人使用的 jar 文件中,我认为让人们按顺序替换他们的 JCE 策略文件不是一个可行的解决方案使用我的图书馆。

第一次遇到这个错误的时候我有点不知所措,因为我之前实际上执行过大约相同的代码并且成功了,但是当我想到它时,我使用的是 OpenJDK 而不是 Oracle 专有的 JDK。当我使用 OpenJDK 时,我也没有遇到加密问题。所以,我在这里似乎有两个错误的选择:

1).强制用户将他们的 Java 开发工具包切换到 OpenJDK,否则我的服务/库将无法运行。

2).强制用户替换其 JRE 的 JCE 策略文件并将 StartCom 证书导入 Java 的 keystore ,例如使用 keytool,或者我可以在运行时加载证书?

这在某种程度上是正确的吗?

编辑2:

以下是我如何使用 http://www.startssl.com/certs/ca-bundle.crt 上提供的证书创建自己的信任库

try {
    // Read the certificate bundle from disk
    CertificateFactory cf = CertificateFactory.getInstance("X.509");
    Certificate ca = cf.generateCertificate(getClass().getResourceAsStream("ca-bundle.crt")); // the file ca-bundle.crt should be in the same folder as your .java files
    // Create a KeyStore containing our trusted CAs
    KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
    keyStore.load(null, null);
    keyStore.setCertificateEntry("ca", ca);
    // Create a TrustStore that trusts the CAs in our KeyStore
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    tmf.init(keyStore);
    // Create an SSLContext that uses our TrustManager
    sslContext = SSLContext.getInstance("TLS");
    sslContext.init(null, tmf.getTrustManagers(), null);
} catch (CertificateException | KeyStoreException | NoSuchAlgorithmException | KeyManagementException | IOException e) {
        e.printStackTrace();
}

现在可以安全地与服务器通信。您可以像这样使用自定义 SSLContext 创建 HttpClient:

CloseableHttpClient client = HttpClients.custom().setSslcontext(sslContext).build();

最佳答案

更新您的 Java 加密扩展:

Java 6 http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html

Java 7 http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html

根据美国法律,默认的 JRE 仅具有有限的加密强度。


编辑: StartCom 的 ROOT CA 证书似乎不在 java 受信任的 CA 中。 使用 openssl 自己将其添加到 JRE 中的 cacerts(请参阅 Digital Certificate: How to import .cer file in to .truststore file)。

您正在构建一个库,只需在 txt 文件的某处放置一个通知(README、HOWTO、FAQ 等),让遇到此问题的人对根 AC 证书执行相同的操作。

关于java - 当我尝试执行 POST 时与 Java 握手失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25358823/

相关文章:

Java:如何在 JFileChooser 中读取 "Files of type"

scala - 如何在 Spray/Scala/Java 中处理通过 HTML 表单上传的文件?

jquery - 为什么 Post 代码在 jQuery 加载时被触发?

jquery - 如何通过 JQuery 登录 ALM

validation - 客户端拒绝服务器证书

amazon-web-services - YAML 解析器错误 : could not found expected : in <unicode string>

java - 单击按钮时不执行方法 [JavaFX]

java - jar在catalina主页的lib文件夹中时,context.xml中类的ClassNotFoundException

java - 参数作为POST方法的请求参数

java - (未知来源)在 StackTrace 中与 Tomcat7、Maven 和 Jensor Profiler