zoukankan      html  css  js  c++  java
  • 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;
        }
    }


    转载出处:
  • 相关阅读:
    [VirtaulBox]网络连接设置
    LeetCode
    LeetCode
    LeetCode
    LeetCode-37.Sudok Solver
    LeetCode-36.Valid Sudoku
    LeetCode-52.N-Queen II
    LeetCode-51.N-Queens
    LeetCode-22.Generate Parentheses
    LeetCode-111.Mininum Depth of Binary Tree
  • 原文地址:https://www.cnblogs.com/flyPenguinblog/p/11243183.html
Copyright © 2011-2022 走看看