接受 Java 中的证书
Posted
技术标签:
【中文标题】接受 Java 中的证书【英文标题】:Accepting certificates in Java 【发布时间】:2012-02-21 23:18:27 【问题描述】:我在通过 Java 与 HTTPS 站点交互时遇到问题。我的程序每次运行时都使用一个带有不受信任证书的 URL。该程序必须在多个系统上运行。目前,我有以下内容:
public class A
HostnameVerifier hv = new HostnameVerifier()
public boolean verify(String urlHostName, SSLSession session)
return true;
;
HttpsURLConnection.setDefaultHostnameVerifier(hv);
javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1];
javax.net.ssl.TrustManager tm = new miTM();
trustAllCerts[0] = tm;
javax.net.ssl.SSLContext sc = null;
try
sc = javax.net.ssl.SSLContext.getInstance("SSL");
catch (NoSuchAlgorithmException e)
e.printStackTrace();
try
sc.init(null, trustAllCerts, null);
catch (KeyManagementException e)
e.printStackTrace();
javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
class miTM implements javax.net.ssl.TrustManager, javax.net.ssl.X509TrustManager
public java.security.cert.X509Certificate[] getAcceptedIssuers()
return null;
public boolean isServerTrusted(java.security.cert.X509Certificate[] certs)
return true;
public boolean isClientTrusted(java.security.cert.X509Certificate[] certs)
return true;
public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) throws java.security.cert.CertificateException
return;
public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) throws java.security.cert.CertificateException
return;
使用这段代码,我可以很好地执行以下操作:
URL url = new URL(urlString);
URLConnection cnx = url.openConnection();
cnx.connect();
InputStream ins = cnx.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(ins));
String curline;
while( (curline = in.readLine()) != null )
System.out.println(curline);
但是,我不能执行以下操作:
httpClient = new HttpClient();
PostMethod postMethod = null;
int intResult = 0;
postMethod = new PostMethod(authURL);
Enumeration emParams = authParams.propertyNames();
while (emParams.hasMoreElements())
String paramName = (String) emParams.nextElement();
String paramValue = authParams.getProperty(paramName);
postMethod.addParameter(paramName, paramValue);
intResult = httpClient.executeMethod(postMethod);
postMethod.releaseConnection();
ins.close();
执行executeMethod(postMethod)时,我得到一个SSLHandshakeException、CertPathBuilderException等。
我能做些什么来解决这个问题?我正在考虑要么接受证书,要么只是绕过所有证书验证(因为程序在专用网络内部运行)。
谢谢
【问题讨论】:
您使用的是 Apache HttpClient 3.x(或 4)吗? 【参考方案1】:看起来您正在使用 Apache HttpClient 3。如果这确实是版本 3,您需要构建自己的 SecureProtocolSocketFactory
,如 Apache HttpClient 3 SSL guide 中所述。有一个example here。
对于 Apache HttpClient 4,您应该能够将 SSLContext
传递给 (HttpClient) SSLSocketFactory
的构造函数,如 the answers to this question 中所述(包括有关主机名验证的说明)。
但是,一般来说,不要遵循这种方法。通过这样做,您实际上完全禁用了 SSL/TLS 连接的身份验证部分,从而使其容易受到 MITM 攻击。
您应该将服务器证书显式导入客户端的信任库中,如this answer 中所述。
我正在考虑要么接受证书,要么只是绕过所有 证书验证(因为程序在内部运行 专用网络)。
您的意思是,您只愿意在您的私有网络内使用 SSL/TLS 进行加密,因为您不够信任其用户,无法查看可能绕过他们机器的流量,但您'还假设这些用户将无法执行 MITM 攻击。这完全没有意义。如果您足够信任他们,您不妨将数据明文发送。如果您不这样做,那么您应该正确实施 SSL/TLS,包括身份验证步骤(证书和主机名验证)。
【讨论】:
谢谢!我使用的是 Apache HttpClient 3.x,但决定使用 4。我遵循了您的建议并且它有效。再次感谢。【参考方案2】:HttpClient 4.3:
HttpClientBuilder cb = HttpClientBuilder.create();
SSLContextBuilder sslcb = new SSLContextBuilder();
sslcb.loadTrustMaterial(KeyStore.getInstance(KeyStore.getDefaultType()), new TrustSelfSignedStrategy());
cb.setSslcontext(sslcb.build());
CloseableHttpClient httpclient = cb.build();
【讨论】:
你能解释一下吗?以上是关于接受 Java 中的证书的主要内容,如果未能解决你的问题,请参考以下文章
JAVA 6 不支持 SNI,还有其他方法可以通过 TLS 验证和接受 SSL 证书吗?