Https通信过程初识和Charles抓包流程

网络初识(一)

CA证书

CA证书:客户端识别自己访问服务端的身份证明。换句话说,客户端访问www.58.com,怎么能确定返回的消息是58服务器返回的数据,而不是假冒网站返回的消息。权威机构为服务器颁发数字证书(怎么认证自己就是本人呢,通过公安局颁发的身份证)。

CA机构:(Certificate Authority)即颁发数字证书的机构。是电子交易、网络数据交流中权威的受信任的第三方机构,承担公钥体系中公钥的合法性检验的责任。(机构私钥A 机构公钥A)机构公钥内置在电脑的操作系统中。

服务器申请证书

  1. 服务器向证书机构申请证书,同时提供自己的域名、地址、公钥等信息。
  2. 证书机构对服务器的信息使用自己的私钥进行非对称加密得到证书
  • 证书机构对服务器的信息使用hash算法得出一份摘要,并对这份摘要使用自己的私钥进行非对称加密得到证书数字签名。
  • 证书机构把服务器信息+数字签名+证书机构信息发送给服务器。
  1. 客户端请求服务器时,服务器把证书返回给客户端。
哈希算法

又称摘要算法: 作用是对任意一组输入数据进行计算,得到一个固定长度的输出摘要。检验数据完整性的重要技术,运算结果具有不可逆性。

客户端验证证书

  1. 客户端拿到证书,得到服务器信息、数字签名、证书机构信息。
  2. 客户端对服务器信息进行哈希算法计算得出一份摘要S1。
  3. 客户端使用证书机构的公钥对数字签名进行解密得到一份摘要S2。
  4. 对比S1和S2即可辨别此证书是否来自服务器且没经过篡改。

证书链

计算机产商,会在系统中安装一些根证书机构的信息,其中就包含了这些机构的公钥。这些公钥是在一定程度上是绝对安全的,是可以信任的。客户端可以使用这些公钥对数字签名进行解密。系统中预装的证书机构是有限的,但世界上每时每刻申请数字证书却非常多,他们“忙不过来”,因此有了二级证书机构。二级证书机构由根证书机构签发,二级证书机构再去给服务器签发证书。

  1. 利用根证书机构给二级证书机构签发的时候同样是一份数字证书,其中包含了二级证书机构信息、数字签名、根证书机构信息。
  2. 服务器的数字证书中包含了二级证书机构的数字证书。
  3. 客户端使用根证书机构的公钥对二级证书机构的数字签名进行解密得到摘要再进行比对,得到二级证书机构的公钥。
  4. 使用二级证书机构的公钥对服务器证书进行验证。

58同城证书

58网页证书链

58网页就是包含了三级的证书机构的证书链

  1. 根证书颁发机构——过期时间:2029年3月18日 星期日 中国标准时间 18:00:00
  2. 中级证书颁发机构——过期时间:2028年11月21日 星期二 中国标准时间 08:00:00
  3. *.58.com——过期时间:2023年3月28日 星期二 中国标准时间 10:51:06

58网页证书

openssl制作CA根证书
  1. 生成java支持的私钥
openssl genrsa -des3 -out ca.key 2048 
openssl pkcs8 -topk8 -nocrypt -inform PEM -outform DER -in ca.key -out ca_private.pem
  1. 再通过CA私钥生成CA证书
openssl req -sha256 -new -x509 -days 365 -key ca.key -out ca.crt \
    -subj "/C=CN/ST=GD/L=SZ/O=lee/OU=study/CN=ProxyeeRoot"

具体可以看这篇文章openssl用法详解

ca证书

Https通信过程

对称加密

对称加密是指加密和解密都用同一份密钥

非对称加密

非对称加密对应于一对密钥,称为私钥和公钥,用私钥加密后需要用公钥解密,用公钥加密后需要用私钥解密

建立连接的过程

  1. 客户端向服务端发起请求,客户端生成随机数R1(ClientRandom) 发送给服务端;告诉服务端自己支持哪些加密算法

Client Hello报文: 作为协商的开始。 报文最主要包含:TLS版本号,随机数(Client Random),密码套件列表,以及sessionID。
其中

  • TLS版本号:用来确定当前TLS采用的版本,目前有TLS1.0,TLS1.1, TLS1.2,TLS1.3。

  • ClientRandom:客户端生成的随机数R1,用于密钥的制作。

  • 密码套件列表:将客户端支持的密码套件全部发给服务端,服务端从中挑选一个密码套件返回客户端。

  • SessionID:用来表示客户端是否想复用先前存在的session。如果不复用,则此字段为0;如果想要复用,则此字段为想要复用的sessionID。是否复用由服务端确定。

  1. 服务器向客户端发送数字证书,服务端生成随机数R2(Server Random),从客户端支持的加密算法中选择一种双方都支持的加密算法(此算法用于后面的会话密钥生成),服务端把证书、随机数R2、加密算法,一同发给客户端;


Server Hello, Certificate, ServerHelloDone共计三个报文

  • ServerHello 报文: 是对ClientHello报文中协商确认的结果。包括:TLS版本号,随机数(Server Random), SerssionID, 加密套件。

  • Certificate 报文:返回数字证书

  • ServerHelloDone 报文:表明服务端的响应已经发送完毕,客户端可以进行后续处理操作;

  1. 客户端验证数字证书。
  • 验证证书的可靠性,先用CA的公钥解密被加密过后的证书,能解密则说明证书没有问题,然后通过证书里提供的摘要算法进行对数据进行摘要,然后通过自己生成的摘要与服务端发送的摘要比对。

  • 验证证书合法性,包括证书是否吊销、是否到期、域名是否匹配,通过后则进行后面的流程

  • 获得公钥、会话密钥生成算法、随机数R2

    • 从服务端证书中得到服务器的公钥、
    • 从服务器返回的数据中得到 会话密钥生成算法、随机数R2
  • 生成一个随机数R3,根据会话秘钥算法使用R1、R2、R3生成会话秘钥

  • 用服务端证书的公钥加密随机数R3并发送给服务端。

  • ClientKeyExchange 报文:携带客户端为密钥交换的所有信息
  • Change Cipher Spec 报文:通知服务端下一个传送的数据采用新的加密方式。
  • Encrypted handshake 报文:用对称秘钥进行加密的第一个报文,如果这个报文加解密校验成功,那么就说明对称秘钥是正确的。

PreMasterKey:是第三个随机数R3

  1. 服务器得到会话密钥

(1)服务器用私钥解密客户端发过来的随机数R3

(2)根据会话秘钥算法使用R1、R2、R3生成会话秘钥

Https通信过程

通信的过程

  1. 客户端使用会话密钥对传输的数据进行对称加密传输给服务器;
  2. 服务器使用会话密钥对传输的数据进行解密;
  3. 服务器使用会话密钥对响应的数据进行对称加密传输给客户端;
  4. 客户端使用会话密钥对传输的数据进行解密;

charles 抓包原理

  1. 客户端向服务器发起HTTPS请求,charles截获客户端发送给服务器的HTTPS请求,charles伪装成客户端向服务器发送请求进行握手。

  2. 服务器发回响应,charles获取到服务器的CA证书,用根证书(内置)公钥进行解密,验证服务器数据签名,获取到服务器CA证书公钥。然后charles伪造自己的CA证书(这里的CA证书,也是根证书,只不过是charles伪造的根证书),冒充服务器证书传递给客户端。

  3. 与普通过程中客户端的操作相同,客户端根据返回的数据进行证书校验、生成R3、用charles伪造的证书公钥加密,并生成HTTPS通信用的对称密钥。

  4. 客户端将重要信息(Charles公钥加密后的随机数)传递给服务器,又被charles截获。charles将截获的密文用自己伪造证书的私钥解开,获得并计算得到HTTPS通信用的对称密钥。charles将客户端发送的数据用服务器证书公钥加密传递给服务器。

  5. 与普通过程中服务器端的操作相同,服务器用私钥解开后建立信任,然后再发送加密的消息给客户端。

  6. charles截获服务器发送的密文,用对称密钥解开,再用自己伪造证书的私钥加密传给客户端。

  7. 客户端拿到加密信息后,用公钥解开,验证HASH。建立连接正式完成,客户端与服务器端就这样建立了”信任“。

charles抓包

正常加密通信过程中:
  1. 服务器—>客户端:charles接收到服务器发送的密文,用对称密钥解开,获得服务器发送的明文。再次加密发送给客户端。
  2. 客户端—>服务端:客户端用对称密钥加密,被charles截获后,解密获得明文。再次加密,发送给服务器端。由于charles一直拥有通信用对称密钥,所以在整个HTTPS通信过程中信息对其透明。

Netty

netty介绍

Netty 是一个 NIO 客户端服务器框架,可以快速轻松地开发协议服务器和客户端等网络应用程序。它极大地简化和流线了网络编程。

Netty核心组件

Handler

为了支持各种协议和处理数据的方式,便诞生了Handler组件。Handler主要用来处理各种事件,这里的事件很广泛,比如可以是连接、数据接收、异常、数据转换等。自己处理的业务需要继承Handler。

ChannelInitializer

当一个链接建立时,需要知道怎么来接收或者发送数据,当然我们有各种各样的Handler实现来处理它,那么ChannelInitializer便是用来配置这些Handler,它会提供一个ChannelPipeline,并把Handler加入到ChannelPipeline。

Pipeline(ChannelPipeline)

ChannelPipeline 是一个 Handler 的集合,它负责处理和拦截 Channel 的入站事件和出站操作,相当于一个贯穿 Netty 的链。ChannelPipeline 实现了一种高级形式的拦截过滤器模式,使用户可以完全控制事件的处理方式,以及 Channel 中各个的 ChannelHandler 如何相互交互。ChannelPipeline负责安排Handler的顺序及其执行

Channels

NIO的基本组件,表示一个打开的连接(网络,文件),可以用于处理一个或者多个不同的I/O操作(读/写)

netty写一个简单的demo

HTTP代理

HTTP:超文本传输协议
HTTP协议传输数据是明文传输,任意的人抓包就能看到传输的数据,试着用netty抓一下HTTP请求,http请求经过代理服务器,代理服务器只要负责转发相应的http响应体就可以了。

public class CustomHttpServer {

    private final int port;

    public CustomHttpServer(int port) {
        this.port = port;
    }

    public static void main(String[] args) throws Exception {
        new CustomHttpServer(8887).start();
    }

    public void start() throws Exception {
        ServerBootstrap b = new ServerBootstrap(); // 引导器,用来配置参数
        NioEventLoopGroup group = new NioEventLoopGroup(); //创建一个线程组:用来处理网络事件(接受客户端连接
        b.group(group)
                .channel(NioServerSocketChannel.class) //使用 NioServerSocketChannel 作为服务器端通道实现
                .childHandler(new ChannelInitializer<SocketChannel>() { // 创建一个通道初始化对象
                    @Override
                    public void initChannel(SocketChannel ch) //往 Pipeline 链中添加自定义的业务
                    throws Exception {
                        System.out.println("initChannel ch:" + ch);
                        ch.pipeline()
                                .addLast("decoder", new HttpRequestDecoder())   // 用于解码request
                                .addLast("encoder", new HttpResponseEncoder())  // 用于编码response
                                .addLast("aggregator", new HttpObjectAggregator(512 * 1024))  // 消息聚合器
                                .addLast("handler", new HttpHandler());        // 自定义的业务处理
                    }
                })
                .option(ChannelOption.SO_BACKLOG, 128) // determining the number of connections queued
                .childOption(ChannelOption.SO_KEEPALIVE, Boolean.TRUE);

        b.bind(port).sync();
    }

    public static class HttpHandler extends SimpleChannelInboundHandler<FullHttpRequest> { // 1

        private AsciiString contentType = HttpHeaderValues.TEXT_PLAIN;

        @Override
        protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {


            System.out.println("gzp_uri:" + msg.getUri());
            if(msg.getUri().startsWith("www.baidu.com")){
                System.out.println("gzp_uri_www.baidu.com:" + msg.getUri());
            }
            if(msg.getUri().startsWith("http://")){
                System.out.println("gzp_uri_http://" + msg.getUri());
                ByteBuf buf= msg.content();
                byte[] bytes= new byte[buf.readableBytes()];//
                buf.getBytes(buf.readerIndex(),bytes);
                String str =new String(bytes);
                System.out.println("gzp_uri_http_content://" + str);
            }
            DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
                    new HttpResponseStatus(200,
                            "Connection established"),
                    Unpooled.wrappedBuffer("<script> alert('this is insert alert   hello android ')</script>".getBytes())); // 2


            HttpHeaders heads = response.headers();
            heads.add(HttpHeaderNames.CONTENT_TYPE, contentType + "; charset=UTF-8");
            heads.add(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes()); // 3
            heads.add(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);

            ctx.write(response); //将数据写到ChannelPipeline中的下一个 ChannelHandler 开始处理
        }

        @Override
        public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
            System.out.println("channelReadComplete");
            super.channelReadComplete(ctx);
            ctx.flush(); // 4
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            System.out.println("exceptionCaught");
            if (null != cause) cause.printStackTrace();
            if (null != ctx) ctx.close();
        }
    }
}

HTTPS代理

  未完待续。。。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340