https、加密安全

1、Https

HTTPS在传输的过程中会涉及到三个密钥:

  服务器端的公钥和私钥,用来进行非对称加密

  客户端生成的随机密钥,用来进行对称加密

 

  一个HTTPS请求实际上包含了两次HTTP传输,可以细分为8步。

  1. 客户端向服务器发起HTTPS请求,连接到服务器的443端口
  2. 服务器端有一个密钥对,即公钥和私钥,是用来进行非对称加密使用的,服务器端保存着私钥,不能将其泄露,公钥可以发送给任何人。
  3. 服务器将自己的公钥发送给客户端
  4. 客户端收到服务器端的公钥之后,会对公钥进行检查,验证其合法性,如果发现发现公钥有问题,那么HTTPS传输就无法继续。严格的说,这里应该是验证服务器发送的数字证书的合法性,关于客户端如何验证数字证书的合法性,下文会进行说明。如果公钥合格,那么客户端会生成一个随机值,这个随机值就是用于进行对称加密的密钥,我们将该密钥称之为client key,即客户端密钥,这样在概念上和服务器端的密钥容易进行区分。然后用服务器的公钥对客户端密钥进行非对称加密,这样客户端密钥就变成密文了,至此,HTTPS中的第一次HTTP请求结束。
  5. 客户端会发起HTTPS中的第二个HTTP请求,将加密之后的客户端密钥发送给服务器。
  6. 服务器接收到客户端发来的密文之后,会用自己的私钥对其进行非对称解密,解密之后的明文就是客户端密钥,然后用客户端密钥对数据进行对称加密,这样数据就变成了密文。
  7. 然后服务器将加密后的密文发送给客户端。
  8. 客户端收到服务器发送来的密文,用客户端密钥对其进行对称解密,得到服务器发送的数据。这样HTTPS中的第二个HTTP请求结束,整个HTTPS传输完成。

 

2、加密与证书:

  安全的获取公钥

     细心的人可能已经注意到了如果使用非对称加密算法,我们的客户端A,B需要一开始就持有公钥,要不没法开展加密行为啊。

这下,我们又遇到新问题了,如何让A、B客户端安全地得到公钥

图片.png

 

 

  client获取公钥最最直接的方法是服务器端server将公钥发送给每一个client用户,但这个时候就出现了公钥被劫持的问题,如上图,client请求公钥,在请求返回的过程中被×××劫持,那么我们将采用劫持后的假秘钥进行通信,则后续的通讯过程都是采用假秘钥进行,数据库的风险仍然存在。在获取公钥的过程中,我们又引出了一个新的话题:如何安全的获取公钥,并确保公钥的获取是安全的, 那就需要用到终极武器了:SSL 证书(需要购买)和CA机构

 

 

SSL证书.png

 

  如上图所示,在第 ② 步时服务器发送了一个SSL证书给客户端,SSL 证书中包含的具体内容有证书的颁发机构、有效期、公钥、证书持有者、签名,通过第三方的校验保证了身份的合法,解决了公钥获取的安全性

 

 

以浏览器为例说明如下整个的校验过程:

(1)首先浏览器读取证书中的证书所有者、有效期等信息进行一一校验

(2)浏览器开始查找操作系统中已内置的受信任的证书发布机构CA,与服务器发来的证书中的颁发者CA比对,用于校验证书是否为合法机构颁发 

(3)如果找不到,浏览器就会报错,说明服务器发来的证书是不可信任的。

(4)如果找到,那么浏览器就会从操作系统中取出  颁发者CA  的公钥,然后对服务器发来的证书里面的签名进行解密

(5)浏览器使用相同的hash算法计算出服务器发来的证书的hash值,将这个计算的hash值与证书中签名做对比

(6)对比结果一致,则证明服务器发来的证书合法,没有被冒充

(7)此时浏览器就可以读取证书中的公钥,用于后续加密了

 

 3、https的java实现

public class HttpsUtil {
    private static Logger logger = LoggerFactory.getLogger(HttpsUtil.class);

    public static JSONObject httpsRequest(String requestUrl, String requestMethod, String outputStr) {
        logger.info("send https requestUrl:"+requestUrl);
        logger.info("send https requestMethod:"+requestMethod);
        logger.info("send https param:"+outputStr);
        JSONObject jsonObject = new JSONObject();
        StringBuffer buffer = new StringBuffer();
        InputStream inputStream = null;
        InputStreamReader inputStreamReader = null;
        BufferedReader bufferedReader = null;
        try {
            // 创建SSLContext对象,并使用我们指定的信任管理器初始化
            TrustManager[] tm = {new MyX509TrustManager()};
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
            sslContext.init(null, tm, new java.security.SecureRandom());
            // 从上述SSLContext对象中得到SSLSocketFactory对象
            SSLSocketFactory ssf = sslContext.getSocketFactory();

            URL url = new URL(requestUrl);
            HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
            httpUrlConn.setSSLSocketFactory(ssf);
            /*允许输出*/
            httpUrlConn.setDoOutput(true);
            /*允许输入*/
            httpUrlConn.setDoInput(true);
            /*不允许缓存*/
            httpUrlConn.setUseCaches(false);
            // 设置请求方式(GET/POST)
            httpUrlConn.setRequestMethod(requestMethod);
            /*如果是get请求,明文连接*/
            if (HttpMethod.GET.toString().equalsIgnoreCase(requestMethod)) {
                httpUrlConn.connect();
            }
            // 当有数据需要提交时
            if (!StringUtils.isEmpty(outputStr)) {
                OutputStream outputStream = httpUrlConn.getOutputStream();
                // 注意编码格式,防止中文乱码
                outputStream.write(outputStr.getBytes("UTF-8"));
                outputStream.close();
            }
            // 将请求返回的输入流转换成字json对象
            inputStream = httpUrlConn.getInputStream();
            inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
            bufferedReader = new BufferedReader(inputStreamReader);
            String str = null;
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }
            httpUrlConn.disconnect();
            jsonObject = (JSONObject) JSONObject.parse(buffer.toString());
            logger.info("response code:"+httpUrlConn.getResponseCode());
            logger.info("response jsonObject:"+jsonObject);
        } catch (ConnectException ce) {
            logger.info("Weixin server connection timed out.");
            throw new BusinessException("Weixin server connection timed out.");
        } catch (Exception e) {
            logger.info("https request error:" + e);
            throw new BusinessException("https request error:" + e);
        } finally {
            try {
                // 释放资源
                bufferedReader.close();
                inputStreamReader.close();
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return jsonObject;
    }
}

 

public class MyX509TrustManager 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 null;
    }
}

 



转载出处:
posted @ 2019-07-25 11:36  啧啧啧花儿不谢呀!  阅读(244)  评论(0编辑  收藏  举报