[英]Java and HTTPS url connection without downloading certificate
此代碼連接到HTTPS站點,我假設我沒有驗證證書。 但為什么我不必在本地為該網站安裝證書? 我不應該在本地安裝證書並為此程序加載它還是在封面下載? 客戶端到遠程站點之間的流量是否仍然在傳輸中加密?
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.net.URLConnection;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class TestSSL {
public static void main(String[] args) throws Exception {
// 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
final 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);
URL url = new URL("https://www.google.com");
URLConnection con = url.openConnection();
final Reader reader = new InputStreamReader(con.getInputStream());
final BufferedReader br = new BufferedReader(reader);
String line = "";
while ((line = br.readLine()) != null) {
System.out.println(line);
}
br.close();
} // End of main
} // End of the class //
但為什么我不必在本地為該網站安裝證書?
那么您正在使用的代碼明確地設計為接受證書而不進行任何檢查。 這不是一個好的做法...但如果這是你想要做的,那么(顯然)不需要安裝你的代碼明確忽略的證書。
我不應該在本地安裝證書並為此程序加載它還是在封面下載?
不,不。 往上看。
客戶端到遠程站點之間的流量是否仍然在傳輸中加密?
是的。 但是,問題在於,由於您已經告訴它在不進行任何檢查的情況下信任服務器的證書,因此您不知道您是在與真實服務器進行通信,還是與正在偽裝成真實服務器的其他站點進行通信。 這是否是一個問題取決於具體情況。
如果我們以瀏覽器為例,通常瀏覽器不會要求用戶為每個訪問過的ssl站點顯式安裝證書。
瀏覽器預先安裝了一組受信任的根證書。 大多數情況下,當您訪問“https”站點時,瀏覽器可以驗證該站點的證書(最終通過證書鏈)是否受到其中一個受信任證書的保護。 如果瀏覽器無法將鏈起始處的證書識別為可信證書(或者證書已過期或無效/不合適),則會顯示警告。
Java的工作方式相同。 JVM的密鑰庫具有一組受信任的證書,並且使用相同的過程來檢查證書是否受可信證書的保護。
java https客戶端api是否支持某種類型的機制來自動下載證書信息?
允許應用程序從隨機位置下載證書,並在系統密鑰庫中安裝它們(如可信)將是一個安全漏洞。
使用最新的X509ExtendedTrustManager而不是X509Certificate,如下所示: java.security.cert.CertificateException:證書不符合算法約束
package javaapplication8;
import java.io.InputStream;
import java.net.Socket;
import java.net.URL;
import java.net.URLConnection;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509ExtendedTrustManager;
/**
*
* @author hoshantm
*/
public class JavaApplication8 {
/**
* @param args the command line arguments
* @throws java.lang.Exception
*/
public static void main(String[] args) throws Exception {
/*
* fix for
* Exception in thread "main" 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
*/
TrustManager[] trustAllCerts = new TrustManager[]{
new X509ExtendedTrustManager() {
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
@Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
@Override
public void checkClientTrusted(X509Certificate[] xcs, String string, Socket socket) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] xcs, String string, Socket socket) throws CertificateException {
}
@Override
public void checkClientTrusted(X509Certificate[] xcs, String string, SSLEngine ssle) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] xcs, String string, SSLEngine ssle) throws CertificateException {
}
}
};
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() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
// Install the all-trusting host verifier
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
/*
* end of the fix
*/
URL url = new URL("https://10.52.182.224/cgi-bin/dynamic/config/panel.bmp");
URLConnection con = url.openConnection();
//Reader reader = new ImageStreamReader(con.getInputStream());
InputStream is = new URL(url.toString()).openStream();
// Whatever you may want to do next
}
}
Java和HTTPS url連接,無需下載證書
如果您確實想避免下載服務器的證書,請使用Anonymous Diffie-Hellman(ADH)等匿名協議。 服務器的證書不會與ADH和朋友一起發送。
您可以使用setEnabledCipherSuites
選擇匿名協議。 您可以使用getEnabledCipherSuites
查看可用的密碼套件列表。
相關:這就是你必須在OpenSSL中調用SSL_get_peer_certificate
的原因。 您將獲得帶有匿名協議的X509_V_OK
,這就是您檢查證書是否在交換中使用的方式。
但正如Bruno和Stephed C所說,避免檢查或使用匿名協議是一個壞主意。
另一種選擇是使用TLS-PSK或TLS-SRP。 它們也不需要服務器證書。 (但我認為你不能使用它們)。
問題是,您需要在系統中預先配置,因為TLS-PSK是預共享密鑰而TLS-SRP是安全遠程密碼 。 身份驗證只是相互而不是服務器。
在這種情況下,相互認證由雙方知道共享秘密並到達相同的預主密鑰的屬性提供; 或者一個(或兩個)沒有,並且通道設置失敗。 每一方都證明秘密的知識是“相互”的一部分。
最后,TLS-PSK或TLS-SRP不會做愚蠢的事情,比如使用HTTP(或通過HTTPS)在Web應用程序中咳嗽用戶的密碼。 這就是為什么我說每一方都證明了這個秘密的知識......
一個簡單的,但不是純Java解決方案,是掏出來curl
從Java,它使您的要求是怎么做的完全控制。 如果你只是為了簡單的事情而這樣做,這允許你有時使用這種方法忽略證書錯誤。 此示例顯示如何針對具有有效或無效證書的安全服務器發出請求,傳入cookie並使用來自java的curl
獲取輸出。
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
public class MyTestClass
{
public static void main(String[] args)
{
String url = "https://www.google.com";
String sessionId = "faf419e0-45a5-47b3-96d1-8c62b2a3b558";
// Curl options are:
// -k: ignore certificate errors
// -L: follow redirects
// -s: non verbose
// -H: add a http header
String[] command = { "curl", "-k", "-L", "-s", "-H", "Cookie: MYSESSIONCOOKIENAME=" + sessionId + ";", "-H", "Accept:*/*", url };
String output = executeShellCmd(command, "/tmp", true, true);
System.out.println(output);
}
public String executeShellCmd(String[] command, String workingFolder, boolean wantsOutput, boolean wantsErrors)
{
try
{
ProcessBuilder pb = new ProcessBuilder(command);
File wf = new File(workingFolder);
pb.directory(wf);
Process proc = pb.start();
BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
StringBuffer sb = new StringBuffer();
String newLine = System.getProperty("line.separator");
String s;
// read stdout from the command
if (wantsOutput)
{
while ((s = stdInput.readLine()) != null)
{
sb.append(s);
sb.append(newLine);
}
}
// read any errors from the attempted command
if (wantsErrors)
{
while ((s = stdError.readLine()) != null)
{
sb.append(s);
sb.append(newLine);
}
}
String result = sb.toString();
return result;
}
catch (IOException e)
{
throw new RuntimeException("Problem occurred:", e);
}
}
}
如果您使用任何支付網關點擊任何網址只是為了發送消息,那么我使用webview遵循它: 如何在android webview中加載https網址而不使用ssl
並且在您的活動中制作網頁視圖並且可見性消失了。 你需要做什么:只需加載webview ..像這樣:
webViewForSms.setWebViewClient(new SSLTolerentWebViewClient());
webViewForSms.loadUrl(" https://bulksms.com/" +
"?username=test&password=test@123&messageType=text&mobile="+
mobileEditText.getText().toString()+"&senderId=ATZEHC&message=Your%20OTP%20for%20A2Z%20registration%20is%20124");
簡單。
你會得到這個:來自這個鏈接的SSLTolerentWebViewClient: 如何在android webview中加載https url而不使用ssl
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.