Java和HTTPS url连接,无需下载证书

Ber*_*own 44 java ssl https

此代码连接到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 //
Run Code Online (Sandbox Code Playgroud)

Bru*_*uno 31

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

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

如果您的服务器证书来自着名的CA,则是与JRE捆绑在一起的默认CA证书捆绑包的一部分(通常是 cacerts文件,请参阅JSSE参考指南),您可以使用默认的信任管理器,您不必设置这里有什么.

如果您具有特定证书(自签名证书或来自您自己的CA),则可以使用默认信任管理器或可能使用特定信任库初始化的证书,但您必须在信任存储中明确导入证书(在独立之后)验证),如本答案所述.您可能也对此答案感兴趣.

  • @BerlinBrown因为浏览器有一个像Java那样的可信CA列表. (2认同)

Ste*_*n C 12

但为什么我不必在本地为该网站安装证书?

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

我不应该在本地安装证书并为此程序加载它还是在封面下载?

不,不.往上看.

客户端到远程站点之间的流量是否仍然在传输中加密?

是的.但是,问题在于,由于您已经告诉它在不进行任何检查的情况下信任服务器的证书,因此您不知道您是在与真实服务器通信,还是与正在伪装成真实服务器的其他站点通信.这是否是一个问题取决于具体情况.


如果我们以浏览器为例,通常浏览器不会要求用户为每个访问过的ssl站点显式安装证书.

浏览器预先安装了一组受信任的根证书.大多数情况下,当您访问"https"站点时,浏览器可以验证该站点的证书(最终通过证书链)是否受到其中一个受信任证书的保护.如果浏览器无法将链起始处的证书识别为可信证书(或者证书已过期或无效/不合适),则会显示警告.

Java的工作方式相同.JVM的密钥库具有一组受信任的证书,并且使用相同的过程来检查证书是否受可信证书的保护.

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

允许应用程序从随机位置下载证书,并在系统密钥库中安装它们(如可信)将是一个安全漏洞.


Tar*_*rik 6

按照此处的建议使用最新的 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

        }

    }
Run Code Online (Sandbox Code Playgroud)