Java 为了轻松的 https 调用,如何接受所有证书
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18894860/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
for rest easy https calls, how to accept all certs
提问by syam
i am trying to call the REST service using jboss rest easy in the following way
我正在尝试通过以下方式使用 jboss rest easy 调用 REST 服务
public ETTestCasePackage getPackageById(String packageId) throws PackageNotFound {
ClientRequest req = new ClientRequest("https://facebook/api");
req.header("Authorization", "Basic " + EztrackerConstants.base64AuthenticationValue);
req.pathParameter("id", packageId);
ETTestCasePackage etPackage = null;
try {
logger.info("invoking "+req.getUri());
//ProxyFactory.create
ClientResponse<ETTestCasePackage> res = req.get(ETTestCasePackage.class);
etPackage = res.getEntity();
} catch (Exception e) {
logger.debug("Not able to retrieve details for testcase package having id = " + packageId, e);
throw new PackageNotFound("Package with id " + packageId + " not found", e);
}
return etPackage;
}
but the above code obviously throw "peer not authenticated";
但上面的代码显然抛出“对等方未通过身份验证”;
javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
at sun.security.ssl.SSLSessionImpl.getPeerCertificates(Unknown Source)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:126)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:437)
at
I can add the respective cert to my local java security jks to solve this. but i may run this so many machines, so cannot do that to all machines. so i want to make my http client accept all request by overridding the http checks.
我可以将相应的证书添加到我的本地 java 安全 jks 来解决这个问题。但我可能会运行这么多机器,所以不能对所有机器都这样做。所以我想让我的 http 客户端通过覆盖 http 检查来接受所有请求。
but for rest easy httprequest, i am not able to find a way to do this. would some one help me in doing for this rest easy.
但是为了轻松的httprequest,我无法找到一种方法来做到这一点。有人会帮我做这个轻松的休息吗?
Thanks in Advance, syam.
提前致谢,赛姆。
I have tried this piece of code calling the actual code for ignoring but still didn't override the default settings. any idea for to make it work for this rest easy client.
我已经尝试过这段代码调用忽略的实际代码,但仍然没有覆盖默认设置。任何让它为这个轻松的客户工作的想法。
private void test(){
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
// Install the all-trusting trust manager
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
}
}
static {
//for localhost testing only
javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(
new javax.net.ssl.HostnameVerifier(){
public boolean verify(String hostname,
javax.net.ssl.SSLSession sslSession) {
return true;
}
});
}
}
回答by Donal Fellows
The easiest method is to get a proper certificate, with a correct DN and signed by a public CA, on each machine on which you are deploying the service. It's bureaucratic and annoying and probably costs real money, but it is definitely easiestoverall.
最简单的方法是在您部署服务的每台机器上获取正确的证书,带有正确的 DN 并由公共 CA 签名。这是官僚主义和烦人的,可能要花真钱,但总体来说绝对是最简单的。
Otherwise, you have to configure the clients to have a verifier that doesn't actually verify. That's dangerous, since anyone at all(including random hackers, organised criminals and dodgy government agencies) can make a self-signed certificate and there's no practical way to detect that they have done so. Except by going through and distributing to everyclient the entire list of server certificates that will everbe used (allowing the verifier to do its check using the club doorman technique: “if you're not on the list, you're not coming in”).
否则,您必须将客户端配置为具有不实际验证的验证器。这很危险,因为任何人(包括随机黑客、有组织的犯罪分子和狡猾的政府机构)都可以制作自签名证书,并且没有切实可行的方法来检测他们是否这样做了。除了通过持续和分发到每一个客户端,将服务器证书的整个列表曾经被使用(允许使用验证俱乐部门卫技术做了检查:“如果你不就行了,你不进来”)。
The verifier is technically going to be some kind of instance of X509TrustManager
.
从技术上讲,验证器将是X509TrustManager
.
回答by Arnelism
Use signed certs as a plan A. As a plan B, when targeting a staging version of another system that you do not control for example, you can use the following solution.
使用签名证书作为计划 A。作为计划 B,例如,当目标是您无法控制的另一个系统的临时版本时,您可以使用以下解决方案。
For Resteasy 3, you need to provide your own all-trusting Httpclient to the client instance. Of course you should never use that in production, so make sure not to hardoce it.
对于 Resteasy 3,您需要向客户端实例提供您自己的全信任 Httpclient。当然,您永远不应该在生产中使用它,因此请确保不要对其进行硬处理。
Normally (using jax-rs 2.0) you'd initialize a client like this:
通常(使用 jax-rs 2.0)你会像这样初始化一个客户端:
javax.ws.rs.client.Client client = javax.ws.rs.client.ClientBuilder.newClient();
For all trusting client, replace it as follows:
对于所有信任的客户端,替换如下:
Client client = null;
if (config.trustAllCertificates) {
log.warn("Trusting all certificates. Do not use in production mode!");
ApacheHttpClient4Engine engine = new ApacheHttpClient4Engine(createAllTrustingClient());
client = new ResteasyClientBuilder().httpEngine(engine).build();
}
else {
client = ClientBuilder.newClient();
}
The createAllTrustingClient() would look like this:
createAllTrustingClient() 看起来像这样:
private DefaultHttpClient createAllTrustingClient() throws GeneralSecurityException {
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
TrustStrategy trustStrategy = new TrustStrategy() {
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
return true;
}
};
SSLSocketFactory factory = new SSLSocketFactory(trustStrategy, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER );
registry.register(new Scheme("https", 443, factory));
ThreadSafeClientConnManager mgr = new ThreadSafeClientConnManager(registry);
mgr.setMaxTotal(1000);
mgr.setDefaultMaxPerRoute(1000);
DefaultHttpClient client = new DefaultHttpClient(mgr, new DefaultHttpClient().getParams());
return client;
}
Just in case you have trouble figuring out the package names of the classes, here are the relevant imports:
以防万一您在弄清楚类的包名称时遇到问题,以下是相关的导入:
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine;
For reference:
以供参考:
回答by Daniel Szalay
To add up on Arnelism's answer: if you are using httpclient-4.2.6.jar
(which is a dependency for resteasy-jaxrs-3.0.10.Final.jar
), you will find that ThreadSafeClientConnManager
is @Deprecated
. You can modify it to BasicClientConnectionManager
or PoolingClientConnectionManager
instead:
加上 Arnelism 的回答:如果您正在使用httpclient-4.2.6.jar
(它是 的依赖项resteasy-jaxrs-3.0.10.Final.jar
),您会发现它ThreadSafeClientConnManager
是@Deprecated
. 您可以将其修改为BasicClientConnectionManager
或PoolingClientConnectionManager
改为:
private static DefaultHttpClient createAllTrustingClient()
throws GeneralSecurityException {
SchemeRegistry registry = new SchemeRegistry();
registry.register(
new Scheme("http", 80, PlainSocketFactory.getSocketFactory())
);
TrustStrategy trustStrategy = new TrustStrategy() {
@Override
public boolean isTrusted(java.security.cert.X509Certificate[] arg0,
String arg1) throws java.security.cert.CertificateException {
return true;
}
};
SSLSocketFactory factory = new SSLSocketFactory(
trustStrategy,
SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER
);
registry.register(new Scheme("https", 443, factory));
BasicClientConnectionManager mgr = new BasicClientConnectionManager(registry);
DefaultHttpClient client =
new DefaultHttpClient(mgr, new DefaultHttpClient().getParams());
return client;
}
回答by Denny
It's necessary to hack the ApacheHttpClient4Executor, the code below is work with HTTPS and will provide a ClientRequest:
有必要破解 ApacheHttpClient4Executor,下面的代码适用于 HTTPS 并提供 ClientRequest:
UriBuilder uri = UriBuilder.fromUri(request.endpoint() + request.path());
System.out.println(request.endpoint() + request.path());
class ApacheHttpClient4Executor2 extends ApacheHttpClient4Executor {
}
ApacheHttpClient4Executor2 executor = new ApacheHttpClient4Executor2();
Scheme http = new Scheme("http", 80, PlainSocketFactory.getSocketFactory());
TrustStrategy trustStrategy = new TrustStrategy() {
@Override
public boolean isTrusted(java.security.cert.X509Certificate[] chain, String authType)
throws CertificateException {
return true;
}
};
SSLSocketFactory factory = null;
try {
factory = new SSLSocketFactory(trustStrategy, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
} catch (KeyManagementException | UnrecoverableKeyException | NoSuchAlgorithmException | KeyStoreException e1) {
e1.printStackTrace();
}
Scheme https = new Scheme("https", 443, factory);
executor.getHttpClient().getConnectionManager().getSchemeRegistry().register(http);
executor.getHttpClient().getConnectionManager().getSchemeRegistry().register(https);
ClientRequest client = new ClientRequest(uri, executor, providerFactory);