如何在 Java 中更改客户端 TLS 首选项? [英] How to change client TLS preferences in Java?
问题描述
我正在尝试使用 Java 向端点发出 POST 请求,当我尝试发送请求时,出现以下错误:
I'm trying to make a POST request to an endpoint in Java, and when I try to send the request, I get the following error:
Caused by: javax.net.ssl.SSLHandshakeException: The server selected protocol version TLS10 is not accepted by client preferences [TLS13, TLS12]
这是我目前所拥有的
Map<Object, Object> data = new HashMap<>();
data.put("username","foo");
data.put("password","bar");
String url = "https://google.com";
HttpRequest request = HttpRequest.newBuilder()
.POST(buildFormDataFromMap(data))
.uri(URI.create(url))
.build();
try{
HttpResponse<String> response = httpClient.send(request,
HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());
} catch (Exception e){
e.printStackTrace();
}
然后当我运行代码时,发送请求/制作响应对象时会抛出错误.我的问题是,如果服务器与客户端的 TLS 首选项不同,我该如何更改 Java 中的首选项,以便它仍然可以发出请求?
Then when I run the code, the error gets thrown when sending the request/making the response object. My question is, if the TLS preferences are different for the server than the client, how can I change the preferences within Java so it can still make the request?
推荐答案
为了在 jdk 11 中解决这个问题,我不得不创建一个 javax.net.ssl.SSLParameters 对象来启用TLSv1"等:
To solve this problem in jdk 11, I had to create an javax.net.ssl.SSLParameters object to enable "TLSv1", etc:
SSLParameters sslParameters = new SSLParameters();
sslParameters.setProtocols(new String[]{"TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"});
然后创建HttpClient并添加sslParamters对象:
Then create the HttpClient and add the sslParamters object:
HttpClient httpClient = HttpClient.newBuilder()
.sslParameters(sslParameters)
.build();
如果您还想禁用主机名验证,请在 HttpClient 初始化之前添加以下代码;
If you also want to disable hostname verification, add following code BEFORE HttpClient initialization;
final Properties props = System.getProperties();
props.setProperty("jdk.internal.httpclient.disableHostnameVerification", Boolean.TRUE.toString());
您也可以添加一个新的 TrustManager 来信任所有证书(自签名).为此,请将以下代码添加到您的类中:
Also you can add a new TrustManager to trust all certificates (self signed). To do so, add following code into your Class:
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
在此之后,您必须创建一个 SSLContext 对象并添加 TrustManger 对象:
After this, you have to create an SSLContext object and add the TrustManger object:
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
最后像这样改变HttpClient初始化:
And finally alter the HttpClient initialization like this:
httpClient = HttpClient.newBuilder()
.sslContext(sslContext)
.sslParameters(sslParameters)
.build()
这是一个完整的类示例:
Here is a complete Class example:
import java.net.http.HttpClient;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.Properties;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class HttpSSLClient {
private SSLContext sslContext;
private SSLParameters sslParameters;
private HttpClient httpClient;
public HttpSSLClient() throws KeyManagementException, NoSuchAlgorithmException {
sslParameters = new SSLParameters();
sslParameters.setProtocols(new String[]{"TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"});
sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
final Properties props = System.getProperties();
props.setProperty("jdk.internal.httpclient.disableHostnameVerification", Boolean.TRUE.toString());
httpClient = HttpClient.newBuilder()
.sslContext(sslContext)
.sslParameters(sslParameters)
.build();
}
public HttpClient getHttplClient() {
return httpClient;
}
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
}
您可以在调用 HttpRequest 时使用 getHttplClient() 函数.
You can use the getHttplClient() function while calling your HttpRequest.
这篇关于如何在 Java 中更改客户端 TLS 首选项?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!