深入理解-HTTP与HTTPS不同之处

一、基本概念

HTTP(超文本传输协议):

        以明文方式发送内容,不提供任何方式的数据加密。

HTTPS(超文本传输安全协议):

        HTTPS = HTTP + 加密 + 身份验证 + 数据完整性。

二、区别之处:

http和https使用的是完全不同的连接方式,用的端口也不同,前者是80,后者是443;

http协议以明文方式发送内容,不提供任何方式的数据加密,https则是具有安全性的ssl加密传输协议。并且https协议需要到ca申请证书。

三、https工作流程:

1.tcp三次握手
2.客户端验证服务器数字证书
3.DH算法协商对称加密算法的秘钥、hash算法的秘钥
4.SSL安全加密隧道协商完成
5.网页以加密的方式传输,用协商的对称加密算法和秘钥加密,保证数据机密性;用协商的hash算法进项数据完整性保护,保证数据不被篡改。

HTTPS协议的主要作用可以分为两种:一种是建立一个信息安全通道,来保证数据传输的安全;另一种就是确认网站的真实性。HTTPS在HTTP的基础上加入了SSL协议,SSL依靠证书来验证服务器的身份,并为浏览器和服务器之间的通信加密。

四、https的加密方案:

对称加密 + 非对称加密  混合使用。

1、对称加密,密钥只有一个,用x加密,用x解密。比如你将要发的数据和密钥x异或一下得到的数据就是加密的,发送过去,再将加密数据与x异或进行解密。
2、非对称加密,有一对密钥,公钥+私钥。用公钥加密就用私钥解密,用私钥加密就用公钥解密。
通过hash散列把数据内容变成固定长度唯一的字符序列->称为数据摘要or数据指纹,再通过加密算法->形成数字签名,通信时将文本内容和数字签名一起发送。怎么检验是否数据被篡改,就拿文本内容同样hash算法成数据指纹,将数字签名解密成数据指纹,进行对比。

而在https中,密钥协商阶段采用非对称加密数据通信阶段采用对称加密。客户端有一个对称加密的密钥下、服务端有非对称的一对密钥,客户端向服务端发送请求说我们商量一下密钥的事,服务端将公钥给客户端,客户端拿着公钥对自己的对称密钥x加密后发给服务端,因为只有服务端有非对称的私钥可以解密,然后服务端用私钥解密拿到客户端对称密钥,之后的数据通信都用对称密钥就可以了。

总结就是:用非对称加密的方式来传输对称加密过程中的密钥,采取对称加密的方式来传输数据。


如果有中间抓包本质问题是:client无法判断发来的密钥协商报文是否从合法服务器发来的。CA机构。
服务器拿着自己的公司信息,域名和公钥向CA机构申请证书,CA机构将服务器的所有信息进行hash散列后用私钥进行加密形成数字签名,此时证书就可以颁发给合法的服务器了。你中间人是可以用CA公钥解密,去修改服务器的私钥,但是你再hash后无法用CA私钥加密了。如果你中间人也去申请证书,但是你证书的域名不是服务器的域名,人家客户端就不会相信你的。

那么,如果需要在你的服务器里调用https的第三方接口,但服务器并没配置openssl证书,这时接口会直接返回错误:

sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target...

处理方式有两种:1.在配置https安全证书;2.代码中创建httpClient使用忽略验证方式。

第二中方式具体代码对比如下:

正常调用http接口:

private static <T> T baseRequest(String url, String token, Class<T> tClass) {
        try {
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
        requestFactory.setConnectTimeout(10000);// 设置超时
        requestFactory.setReadTimeout(10000);
            RestTemplate restTemplate = new RestTemplate(requestFactory);
            HttpHeaders httpHeaders = new HttpHeaders();
            httpHeaders.add("Authorization", "Bearer " + token);
            httpHeaders.setContentType(MediaType.APPLICATION_JSON);
            HttpEntity<T> httpEntity = new HttpEntity<>(null, httpHeaders);
            ResponseEntity<T> responseEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, tClass);

            if (200 == responseEntity.getStatusCode().value()) {
                return responseEntity.getBody();
            } else {
                log.error("错误信息:\r\n" + responseEntity + "\r\n");
            }
        } catch (Exception e) {
            log.error("错误信息:\r\n" + e.getMessage() + "\r\n");
        }
        return null;
    }
改用http忽略验证方式:
  private static <T> T baseRequest(String url, String token, Class<T> tClass) {
        try {
            IgnoreSSLRequestFactory requestFactory = new IgnoreSSLRequestFactory(httpClient());
            requestFactory.setConnectTimeout(60000); //连接上服务器(握手成功)的时间
            requestFactory.setReadTimeout(60000);
            RestTemplate restTemplate = new RestTemplate(requestFactory);
            HttpHeaders httpHeaders = new HttpHeaders();
            httpHeaders.add("Authorization", "Bearer " + token);
            httpHeaders.setContentType(MediaType.APPLICATION_JSON);
            HttpEntity<T> httpEntity = new HttpEntity<>(null, httpHeaders);
            ResponseEntity<T> responseEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, tClass);

            if (200 == responseEntity.getStatusCode().value()) {
                return responseEntity.getBody();
            } else {
                log.error("错误信息:\r\n" + responseEntity + "\r\n");
            }
        } catch (Exception e) {
            log.error("错误信息:\r\n" + e.getMessage() + "\r\n");
        }
        return null;
    }

 private static HttpClient httpClient() throws KeyManagementException, NoSuchAlgorithmException {
        SSLContextBuilder contextBuilder = new SSLContextBuilder();
        SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(contextBuilder.build(), NoopHostnameVerifier.INSTANCE);
        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", new PlainConnectionSocketFactory())
                .register("https", socketFactory).build();
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
        connectionManager.setMaxTotal(200);
        connectionManager.setDefaultMaxPerRoute(100);
        CloseableHttpClient httpClient = HttpClientBuilder.create().setConnectionManager(connectionManager).build();
        return httpClient;
    }

import org.apache.http.client.HttpClient;
import org.springframework.http.client.SimpleClientHttpRequestFactory;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

/**
 * 绕过证书
 */
public class IgnoreSSLRequestFactory extends SimpleClientHttpRequestFactory {

    public IgnoreSSLRequestFactory(HttpClient httpClient) {
        super();
    }

    @Override
    protected void prepareConnection(HttpURLConnection connection, String httpMethod)
            throws IOException {
        if (connection instanceof HttpsURLConnection) {
            prepareHttpsConnection((HttpsURLConnection) connection);
        }
        connection.setConnectTimeout(3000);
        connection.setReadTimeout(3000);
        super.prepareConnection(connection, httpMethod);
    }

    private void prepareHttpsConnection(HttpsURLConnection connection) {
        connection.setHostnameVerifier(new SkipHostnameVerifier());
        try {
            connection.setSSLSocketFactory(createSslSocketFactory());
        } catch (Exception ex) {
            // Ignore
        }
    }

    private SSLSocketFactory createSslSocketFactory() throws Exception {
        SSLContext context = SSLContext.getInstance("TLS");
        context.init(null, new TrustManager[]{new SkipX509TrustManager()},
                new SecureRandom());
        return context.getSocketFactory();
    }

    private class SkipHostnameVerifier implements HostnameVerifier {

        @Override
        public boolean verify(String s, SSLSession sslSession) {
            return true;
        }

    }

    private static class SkipX509TrustManager implements X509TrustManager {


        @Override
        public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

        }

        @Override
        public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
        }
    }
}

读完的同学,你学废了吗?

知识点扩展:

RSA非对称加密算法;
DSA数字签名算法;
ECDSA椭圆曲线签名算法;

有兴趣的同学可以深入学习。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值