HTTPS

 
防止内容被第三方冒充或者篡改

SSL/TLS协议及握手过程

 
(4)服务器使用私钥得到key,并用key对数据加密,在相同的输入参数下能得到跟客户端传来的一样的数据。

 
这个异常就是HTTPS握手的过程中出现了问题。

 

数字证书

 
通过这种方式,黑客就不能简单的修改证书中的公钥了,因为公钥有了CA的数字签名,由CA证明公钥的有效性,不能被轻易篡改。

 

12306的证书问题

 

 
同样,操作系统也保存了一份可信的证书列表,可以运行certmgr.msc打开证书管理器查看,这些证书实际上是存储在Windows的注册表中,一般在\SOFTWARE\Microsoft\SystemCertificates\下。

 

 
(5)利用SSLContext产生的SSLSocket和SSLServerSocket进行通信

 
对于非CA机构颁发的证书和自签名证书,我们是无法直接访问到服务器的,直接访问通常会抛出异常:

javax.net.ssl.SSLHandshakeException:
java.security.cert.CertPathValidatorException:
Trust anchor forcertification path not found.

有两种方法可以通过忽略证书直接调用: 
方法一:自定义TrustManager绕过证书检查

@Test
public void basicHttpsGetIgnoreCertificateValidation() throws Exception {
     
    String url = "https://kyfw.12306.cn/otn/";
     
    // Create a trust manager that does not validate certificate chains
    TrustManager[] trustAllCerts = new TrustManager[] {
        new X509TrustManager() {
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
            public void checkClientTrusted(X509Certificate[] certs, String authType) {
                // don't check
            }
            public void checkServerTrusted(X509Certificate[] certs, String authType) {
                // don't check
            }
        }
    };
     
    SSLContext ctx = SSLContext.getInstance("TLS");
    ctx.init(null, trustAllCerts, null);
     
    LayeredConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(ctx);
     
    CloseableHttpClient httpclient = HttpClients.custom()
            .setSSLSocketFactory(sslSocketFactory)
            .build();
     
    HttpGet request = new HttpGet(url);
    request.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) ...");
     
    CloseableHttpResponse response = httpclient.execute(request);
    String responseBody = readResponseBody(response);
    System.out.println(responseBody);
}

方法二:信任所有证书

@Test
public void basicHttpsGetIgnoreCertificateValidation() throws Exception {
    
        SSLContextBuilder builder = new SSLContextBuilder();
        //JAVA8支持的新语法
        //TrustStrategy acceptingTrustStrategy = ((X509Certificate[] certificate,String type) -> true);
        //builder.loadTrustMaterial(null, acceptingTrustStrategy);
        
        //上面这两步可以这么写:
        builder.loadTrustMaterial(new TrustStrategy(){
            @Override
            public boolean isTrusted(X509Certificate[] arg0, String arg1)
                    throws CertificateException {
                return true;
            }
        });
        
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build());
        CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(
            sslsf).build();
            HttpGet httpGet = new HttpGet("https://some-server");
    CloseableHttpResponse response = httpclient.execute(httpGet);
    try {
        System.out.println(response.getStatusLine());
        HttpEntity entity = response.getEntity();
        EntityUtils.consume(entity);
    }
    finally {
        response.close();
    }
}

方法二虽然解决了SSHHandshakeException异常,但是由于客户端信任所有的证书,反而存在更大的隐患。

单向验证且服务器证书可信

package com.ydd.study.hello.httpclient;
/**
 * @COPYRIGHT (C) 2018 Schenker AG
 * <p/>
 * All rights reserved
 */

import org.apache.http.HttpHost;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;


public class oneWayAuthTest {
    public static CloseableHttpClient httpclient;

    // 获得池化得HttpClient
    static {
        // 设置truststore
        SSLContext sslcontext = null;
        try {
            sslcontext = SSLContexts.custom()
                                    .loadTrustMaterial(new File("D://https//ca//cl.jks"),
                                    "123456".toCharArray(), new TrustSelfSignedStrategy())
                                    .build();
        }
        catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        // 客户端支持TLSV1,TLSV2,TLSV3这三个版本
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                sslcontext, new String[]{"TLSv1", "TLSv2", "TLSv3"}, null,
                SSLConnectionSocketFactory.getDefaultHostnameVerifier());// 客户端验证服务器身份的策略

        // Create a registry of custom connection socket factories for supported
        // protocol schemes.
        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder
                .<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.INSTANCE)
                .register("https", new SSLConnectionSocketFactory(sslcontext))
                .build();
        PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(
                socketFactoryRegistry);
        // Configure total max or per route limits for persistent connections
        // that can be kept in the pool or leased by the connection manager.
        connManager.setMaxTotal(100);
        connManager.setDefaultMaxPerRoute(10);
        // 个性化设置某个url的连接
        connManager.setMaxPerRoute(new HttpRoute(new HttpHost("www.y.com",
                80)), 20);
        httpclient = HttpClients.custom().setConnectionManager(connManager)
                .build();

    }

    /**
     * 单向验证且服务端的证书可信
     * @throws IOException
     * @throws ClientProtocolException
     */
    public static void oneWayAuthorizationAccepted() throws ClientProtocolException, IOException {
        // Execution context can be customized locally.
        HttpClientContext context = HttpClientContext.create();
        HttpGet httpget = new HttpGet("https://www.yunzhu.com:8443");
        // 设置请求的配置
        RequestConfig requestConfig = RequestConfig.custom()
                .setSocketTimeout(5000).setConnectTimeout(5000)
                .setConnectionRequestTimeout(5000).build();
        httpget.setConfig(requestConfig);

        System.out.println("executing request " + httpget.getURI());
        CloseableHttpResponse response = httpclient.execute(httpget, context);
        try {
            System.out.println("----------------------------------------");
            System.out.println(response.getStatusLine());
            System.out.println(EntityUtils.toString(response.getEntity()));
            System.out.println("----------------------------------------");

            // Once the request has been executed the local context can
            // be used to examine updated state and various objects affected
            // by the request execution.

            // Last executed request
            context.getRequest();
            // Execution route
            context.getHttpRoute();
            // Target auth state
            context.getTargetAuthState();
            // Proxy auth state
            context.getTargetAuthState();
            // Cookie origin
            context.getCookieOrigin();
            // Cookie spec used
            context.getCookieSpec();
            // User security token
            context.getUserToken();

        } catch (Exception e) {
            e.printStackTrace();
        }

    }
    public static void main(String[] a) throws KeyManagementException,
            NoSuchAlgorithmException, KeyStoreException, CertificateException,
            IOException {
        oneWayAuthorizationAccepted();
    }

}

 

相关文章: