关于HttpUrlConnection请求网络加载证书与不加载证书的区别

关于https网络请求这一块,个人感觉内容挺多的,多到难以理解,于是不自觉的又动手研究了下。关于https的有关介绍,我这里推荐一个博客:https原理:证书传递、验证和数据加密、解密过程解析,下面是我测试HttpUrlConnection的日志:

测试的3个网址分别为:

String uri1 = "https://mportal.tianjihuifu.com/tjhf/loginRegist/login?uname=13265468238&pwd=123456";

String uri2 = "https://mportal.tjhf.com/tjhf/loginRegist/login?uname=13265468238&pwd=123456";

String uri = "https://www.baidu.com/";


中间用到的证书为cer_test.crt,证书信息为:CN=console.haitest.com, C=CN。分别测试了加载证书与不加载证书请求3个不同的网址的日志。

  • 证书为cer_test.crt,没有HostnameVerifier

 E/==####DROXY####===: (*_*)发送请求(get):https://mportal.haitest.com/hai/loginRegist/login?uname=13265468238&pwd=123456
 E/==####DROXY####===: (*_*)响应结果:{"data":72771,"result":true,"resultCode":2000}
 E/==####DROXY####===: (*_*)发送请求(get):https://mportal.hai.com/hai/loginRegist/login?uname=13265468238&pwd=123456
 W/System.err: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
 E/==####DROXY####===: (*_*)发送请求(get):https://www.baidu.com/
 W/System.err: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
  • 证书为cer_test.crt,HostnameVerifier :return true
 E/==####DROXY####===: (*_*)发送请求(get):https://mportal.haitest.com/hai/loginRegist/login?uname=13265468238&pwd=123456
 E/==####DROXY####===: (*_*)响应结果:{"data":72771,"result":true,"resultCode":2000}
 E/==####DROXY####===: (*_*)发送请求(get):https://mportal.hai.com/hai/loginRegist/login?uname=13265468238&pwd=123456
 W/System.err: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
 E/==####DROXY####===: (*_*)发送请求(get):https://www.baidu.com/
 W/System.err: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
  • 证书为cer_test.crt,HostnameVerifier :return hostname.equals(session.getPeerHost())
 E/==####DROXY####===: (*_*)发送请求(get):https://mportal.haitest.com/hai/loginRegist/login?uname=13265468238&pwd=123456
 E/==####DROXY####===: (*_*)响应结果:{"data":72771,"result":true,"resultCode":2000}
 E/==####DROXY####===: (*_*)发送请求(get):https://mportal.hai.com/hai/loginRegist/login?uname=13265468238&pwd=123456
W/System.err: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
 E/==####DROXY####===: (*_*)发送请求(get):https://www.baidu.com/
 W/System.err: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
  • 证书为null,没有HostnameVerifier
E/==####DROXY####===: (*_*)发送请求(get):https://mportal.haitest.com/hai/loginRegist/login?uname=13265468238&pwd=123456
E/==####DROXY####===: (*_*)发送请求(get):https://mportal.hai.com/hai/loginRegist/login?uname=13265468238&pwd=123456
E/==####DROXY####===: (*_*)响应结果:{"data":72771,"result":true,"resultCode":2000}
E/==####DROXY####===: (*_*)发送请求(get):https://www.baidu.com/
E/==####DROXY####===: (*_*)响应结果:<!DOCTYPE html>

                      <html><!--STATUS OK--><script>var PageTimer = {};PageTimer.start = new Date().getTime();</

测试结果总结得出:HttpURLConnection连接网络

  1. 无加载证书,可以请求任何https网址,
  2. 加载证书,且信任证书密钥,则只能请求和证书网址一致的网址,不管HostnameVerifier返回的是true or false
  3. 加载证书,且信任所有证书,则可以请求任何https网址,
  4. 只要是https网址,不管有没有使用sslSocketFactory,传输的都是加密密文
下面给出网络请求的主要部分代码

/**
 * Created by 黄海 on 2016/10/8.
 */
public class HttpUtils {
    private static final String BOUNDARY = "------WebKitFormBoundaryXt9bHBmce2A1Qt0j";
    private static final int CONNECTION_TIMEOUT = 7 * 1000;
    private static final int SOCKET_TIMEOUT = 7 * 1000;
    private static SSLSocketFactory sslSocketFactory;
    private static CookieManager cookieManager;
    private static final String COOKIES_HEADER = "Set-Cookie";
    private static Map<String, String> requestHeader = new HashMap<>();

    public static void init(Context context) {
        cookieManager = new CookieManager();
        CookieHandler.setDefault(cookieManager);//如果这里设置了,就不需要手动管理cookie了

        KeyStore keyStore = null;
        InputStream is = null;
        CertificateFactory cf = null;

        try {
            cf = CertificateFactory.getInstance("X.509");
            is = context.getResources().getAssets().open("cer_test.crt");
            Certificate ca = cf.generateCertificate(is);
            Logger.e("ca=" + ((X509Certificate) ca).getSubjectDN());

            // Create a KeyStore containing our trusted CAs
            keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null, null);
            keyStore.setCertificateEntry("ca", ca);

            // Create a TrustManager that trusts the CAs in our KeyStore
            String defaultAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(defaultAlgorithm);
            tmf.init(keyStore);

            // Create an SSLContext that uses our TrustManager
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, tmf.getTrustManagers(), null);//信任证书密钥
//            sslContext.init(null, new TrustManager[]{new UnSafeTrustManager()}, null);//信任所有
            sslSocketFactory = sslContext.getSocketFactory();

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

    public static String get(String uri) {
        try {
            byte[] bytes = performRequest(new URL(uri), null, null, Method.GET);
            if (bytes != null && bytes.length > 0) {
                String result = new String(bytes);
                Logger.e("响应结果:" + result);
                return result;
            } else {
                Logger.e("请求出错:请检查好网络设置");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String post(String url, Map<String, File> files) {
        try {
            byte[] bytes = performRequest(new URL(url), null, files, Method.POST);
            if (bytes != null && bytes.length > 0) {
                String result = new String(bytes);
                Logger.e("响应结果:" + result);
                return result;
            } else {
                Logger.e("请求出错:请检查好网络设置");
            }
        } catch (Exception e) {
            Logger.e("请求出错:请检查好网络设置");
            e.printStackTrace();
        }
        return null;
    }

    private static byte[] performRequest(URL url, byte[] params, Map<String, File> files, int method) throws Exception {
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setConnectTimeout(CONNECTION_TIMEOUT);
        connection.setReadTimeout(SOCKET_TIMEOUT);
        connection.setUseCaches(false);
        connection.setDoInput(true);
        if ("https".equals(url.getProtocol()) && sslSocketFactory != null) {
            ((HttpsURLConnection) connection).setSSLSocketFactory(sslSocketFactory);
            ((HttpsURLConnection) connection).setHostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    Log.e("hhp", "verify: " + hostname + "|" + session.getPeerHost());
                    return hostname.equals(session.getPeerHost());
//                    return true;
                }
            });
        }
        //设置请求头
        for (String headerName : getRequestHeader().keySet()) {
            connection.addRequestProperty(headerName, getRequestHeader().get(headerName));
        }
        //设置cookie
//        if (cookieManager.getCookieStore().getCookies().size() > 0) {
//            connection.setRequestProperty("Cookie",
//                    TextUtils.join(";", cookieManager.getCookieStore().getCookies()));
//            Logger.i("Cookie=" + connection.getRequestProperty("Cookie"));
//        }
        setConnectionParametersForRequest(connection, params, method);
//        setConnectionParametersForRequest(connection, files);

        int responseCode = connection.getResponseCode();
        if (responseCode != 200) {
            Logger.e("请求出错:responseCode=" + responseCode);
            throw new IOException("Could not retrieve response code from HttpUrlConnection.");
        }
        if (hasResponseBody(method, responseCode)) {
//            readResponseCookies(url, connection);
            InputStream inputStream;
            try {
                inputStream = connection.getInputStream();
            } catch (IOException ioe) {
                inputStream = connection.getErrorStream();
            }
            if (inputStream != null) {
                int length = connection.getContentLength();
                byte[] buffer = new byte[length];
                inputStream.read(buffer);
                return buffer;
            }
        }
        return new byte[0];
    }

    /**
     * 设置请求参数
     *
     * @param connection
     * @param postBody
     * @param method
     * @throws IOException
     */
    private static void setConnectionParametersForRequest(HttpURLConnection connection, byte[] postBody, int method) throws IOException {
        switch (method) {
            case Method.POST:
                byte[] body = postBody;
                if (body != null) {
                    connection.setDoOutput(true);
                    connection.setRequestMethod("POST");
                    connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
                    DataOutputStream out = new DataOutputStream(connection.getOutputStream());
                    out.write(postBody);
                    out.close();
                }
                break;
            case Method.GET:
                connection.setRequestMethod("GET");
                Logger.e("发送请求(get):" + connection.getURL().toString());
                break;
        }
    }

    /**
     * 上传文件
     *
     * @param connection
     * @param files
     * @throws IOException
     */
    private static void setConnectionParametersForRequest(HttpURLConnection connection, Map<String, File> files) throws IOException {
        String contentType = "application/octet-stream";
//        String contentType="image/jpeg";
        if (files != null && files.size() > 0) {
            connection.setDoOutput(true);
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
            DataOutputStream out = new DataOutputStream(connection.getOutputStream());
            Iterator<Map.Entry<String, File>> iterator = files.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, File> next = iterator.next();
                String name = next.getKey();
                File value = next.getValue();
                if (value == null)
                    return;
                StringBuilder strBuf = new StringBuilder();
                strBuf.append("\r\n").append("--").append(BOUNDARY).append("\r\n");
                strBuf.append("Content-Disposition: form-data; name=\"" + name + "\"; filename=\"" + value.getName() + "\"\r\n");
                strBuf.append("Content-Type:" + contentType + "\r\n\r\n");
                out.write(strBuf.toString().getBytes());
                DataInputStream dis = new DataInputStream(new FileInputStream(value));
                int bytes = -1;
                byte[] buffer = new byte[1024 * 4];
                while ((bytes = dis.read(buffer)) != -1) {
                    out.write(buffer);
                }
                dis.close();
            }
            byte[] endData = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();
            out.write(endData);
            out.flush();
            out.close();
        }
        Logger.e("发送请求(post):" + connection.getURL().toString());
        if (files != null) {
            for (File file : files.values()) {
                Logger.e("发送文件:" + new String(file.getName()));
            }
        }
    }

    private static Map<String, String> getRequestHeader() {
        requestHeader.put("Connection", "Keep-Alive");
        requestHeader.put("Accept-Encoding", "identity");//高版本避免conn.getContentLength()==-1;
        requestHeader.put("X-Flag", "TJHF");
        requestHeader.put("Channel", "tjhf");
        return requestHeader;
    }

    public interface Method {
        int GET = 1;
        int POST = 2;
        int HEAD = 4;
    }

    /**
     * 存储cookies
     *
     * @param url
     * @param connection
     * @throws URISyntaxException
     */
    private static void readResponseCookies(URL url, HttpURLConnection connection) throws URISyntaxException {
        Map<String, List<String>> headerFields = connection.getHeaderFields();
        final List<String> cookiesHeader = headerFields.get(COOKIES_HEADER);
        if (cookiesHeader != null) {
            for (String cookie : cookiesHeader) {
                cookieManager.getCookieStore().add(url.toURI(), HttpCookie.parse(cookie).get(0));
            }
        }
    }

    private static boolean hasResponseBody(int requestMethod, int responseCode) {
        return requestMethod != Method.HEAD
                && !(HttpStatus.SC_CONTINUE <= responseCode && responseCode < HttpStatus.SC_OK)
                && responseCode != HttpStatus.SC_NO_CONTENT
                && responseCode != HttpStatus.SC_NOT_MODIFIED;
    }
}

自定义的信任规则管理器

package hai.com.android_test.mixed;
import javax.net.ssl.X509TrustManager;

/**
 * 不安全的信任管理
 */
public class UnSafeTrustManager implements X509TrustManager {
    @Override
    public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws java.security.cert.CertificateException {
    }
    @Override
    public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws java.security.cert.CertificateException {
    }
    @Override
    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
        return new java.security.cert.X509Certificate[0];
    }
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值