不下载证书的Java和HTTPS url连接

不下载证书的Java和HTTPS url连接,java,ssl,https,Java,Ssl,Https,此代码连接到HTTPS站点,我假设我没有验证证书。但是为什么我不需要在本地为站点安装证书呢?我不应该在本地安装证书并为这个程序加载它吗?或者它是在后台下载的吗?客户端到远程站点之间的通信在传输过程中是否仍然加密 import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.Reader; import java.net.URL; import java.net.URLConnection; impo

此代码连接到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 //

您不必在本地加载证书的原因是,您已明确选择不验证证书,此信任管理器信任所有证书

流量仍将被加密,但您正在打开与中间人攻击的连接:您正在与某人秘密通信,您只是不确定这是您期望的服务器,还是可能的攻击者

如果您的服务器证书来自著名的CA,这是与JRE捆绑在一起的默认CA证书捆绑包的一部分(通常
cacerts
文件,请参阅JSSE参考指南),您只需使用默认的信任管理器,无需在此处设置任何内容

如果您有一个特定的证书(自签名或来自您自己的CA),则可以使用默认的信任管理器,也可以使用一个使用特定信任库初始化的证书,但您必须在信任库中显式导入证书(独立验证后),如中所述。你也可能对这一点感兴趣

但是为什么我不需要在本地为站点安装证书呢

您使用的代码被明确设计为接受证书而不进行任何检查。这不是好的做法。。。但是,如果这是您想要做的,那么(显然)不需要安装代码显式忽略的证书

我不应该在本地安装证书并为这个程序加载它吗?或者它是在后台下载的吗

不,不。见上文

客户端到远程站点之间的通信在传输过程中是否仍然加密

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的密钥库有一组受信任的证书,使用相同的过程检查证书是否由受信任的证书保护

JavaHTTPS客户端api是否支持某种类型的自动下载证书信息的机制

不允许。允许应用程序从任意位置下载证书,并将其(作为受信任的)安装到系统密钥库中,这将是一个安全漏洞

不下载证书的Java和HTTPS url连接

如果您确实希望避免下载服务器的证书,那么请使用匿名协议,如anonymous Diffie Hellman(ADH)。服务器的证书未与ADH和朋友一起发送

您可以使用
设置启用的iPhone套件
选择匿名协议。您可以查看
GetEnabledCipherSuite
提供的密码套件列表

相关:这就是为什么您必须在OpenSSL中调用
SSL\u get\u peer\u certificate
。您将获得一个带有匿名协议的
X509_V_OK
,这就是您检查exchange中是否使用了证书的方式

但正如布鲁诺和斯蒂芬C所说,避免检查或使用匿名协议是个坏主意


另一种选择是使用TLS-PSK或TLS-SRP。它们也不需要服务器证书。(但我认为你不能使用它们)

问题是,您需要在系统中预先设置,因为TLS-PSK是Pres共享密码,TLS-SRP是安全的远程密码。身份验证是相互的,而不仅仅是服务器

在这种情况下,相互认证由双方都知道共享秘密并获得相同的主密钥的属性提供;或者一个(或两个)不存在,并且通道设置失败。每一方都证明知道这个秘密是“共同的”部分


最后,TLS-PSK或TLS-SRP不会做愚蠢的事情,比如像在使用HTTP(或HTTPS)的web应用程序中一样,说出用户的密码。这就是为什么我说每一方都证明了这个秘密…

一个简单但不是纯java的解决方案,就是从java向
curl
抛售,它让您完全控制请求是如何完成的。如果您只是为了一些简单的事情而这样做,那么通过使用此方法,您有时可以忽略证书错误。此示例演示如何使用有效或无效证书对安全服务器发出请求,传入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);
    }
  }


}

使用最新的X509ExtendedTrustManager,而不是此处建议的X509Certificate:


如果您使用任何支付网关点击任何url只是为了发送消息,那么我使用了webview,方法如下:

并在活动中创建一个Web视图,使可见性消失。您需要做的是:只需加载该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:

如果我们以浏览器为例,通常浏览器不会要求用户