前言:为保证网络应用,特别是应用广泛的Web应用数据传输的安全性(机密性、完整性和真实性),可以在多个网络层次上采取安全措施。本篇主要介绍传输层提供应用数据安全传输服务的协议,包括:安全套接字层(SSL)、传输层安全协议(TLS)以及SSL/TLS VPN。
目录
- 1. 传输层安全问题
-
- 1.1 UDP
- 1.2 TCP
- 2. SSL
-
- 2.1 Web安全需求
- 2.2 SSL体系结构
-
- 2.2.1 SSL记录协议
- 2.2.2 SSL密码变更规格协议
- 2.2.3 Alert协议
- 2.2.4 握手协议
- 2.2.5 密钥生成
- 2.3 SSL实现的安全服务
- 2.4 SSL的安全性分析
- 3. TLS
-
- 3.1 TLS与SSL的差异
- 3.2 TLS 1.3
- 4. SSL/TLS VPN
1. 传输层安全问题
为保证网络应用间,特别是应用广泛的Web应用数据传输的安全性(机密性、完整性和真实性),可以在多个网络层次上采取安全措施。
1.1 UDP
UDP协议可用于风暴型DDoS。
- 由于UDP协议不需要与目标建立连接,因此攻击者很容易通过伪造源地址的方式向目标发送攻击报文,非常简单易行
- 攻击者利用控制的僵尸网络中的大量主机向攻击目标(主机或网络设备)发送大量的 UDP数据包,使其忙于处理和回应 UDP 报文,导致目标设备不能提供正常服务或者直接死机,严重的会造成全网瘫痪。
1.2 TCP
安全性分析:
- 端口扫描(TCP Connect扫描、TCP SYN扫描、TCP FIN扫描、Xmas扫描和Null扫描)
- 拒绝服务(DoS)攻击(TCP SYN Flooding)
- TCP会话劫持攻击(第三方伪造身份)
- 只要TCP包中的源端口、目的端口、
Seq、Ack
正确,即可被正确接收。当得到入侵者构造的TCP数据包,协议会假设数据包是来源于TCP连接中另一方的合法数据包,并且发送响应包到(入侵者构造的数据包中设置的IP地址)。随后,原来的TCP连接会由于计数器不匹配而断开连接。 - 关键:猜测
Seq、Ack
,如果是旁路劫持还需猜测源端口号
- 只要TCP包中的源端口、目的端口、
TCP的厄运:网络协议侧信道分析及利用
Man-in-the-middle vs. Off-path attacks
- Man-in-the-middle attacks
- On the communication path
- Harder but possible: open wifi,route hijack, etc.
- Prevention with crypto: PKl, complexity, overhead.
Caching (HTTP-only)
in mobile networks- Why bother,
- Off-path attacks
- Off the communication path
- Cannot intercept/modify/block traffic
- Prevention with challenge-response (e.g., cookie)
- Subject to prediction or side channel attacks!
Off-path TCP Sequence Number Inference Attack – How Firewall Middleboxes Reduce Security
Off-Path TCP Exploits: Global Rate Limit Considered
Dangerous
Off-Path TCP Exploit: How Wireless Routers Can Jeopardize Your Secrets
简答题:简述TCP连接劫持的攻击原理和应对措施
答:通过一些手段和方式推测客户端和服务器端通信过程的正在使用的端口号和序列号进而劫持连接,让客户端和服务器端和我们沟通。应对措施:推测序列号的范围,并给出最准确的值。
2. SSL
2.1 Web安全需求
由于Web应用协议主要通过传输层的TCP协议来传输其协议报文,而TCP协议不支持加密和认证,因此并不能保证Web应用传输上的安全
- 网景公司(Netscape)于1994年开发了安全套接字(Security Socket Layer, SSL)协议
- SSL版本:2.0 (1995年)、3.0 (1996年,2011年RFC6101)
2.2 SSL体系结构
SSL利用TCP协议为上层应用提供端到端的安全传输服务,包括认证和加密
SSL几个协议之间的关系是:
- 使用握手协议协商加密和MAC算法以及保密密钥,以及身份认证
- 使用密码变更规格协议变更连接上使用的密码机制
- 使用记录协议对交换的数据进行加密和签名
- 使用告警协议定义数据传输过程中出现的问题并通知相关方
SSL两个重要概念
- 连接(connection):是指一种能够提供合适服务类型的传输通道。对SSL来说,这种连接是点对点、暂时的。每条连接都与一个会话关联
- 会话(session):是指客户与服务器之间的一种关联,由握手协议创服务器托管网建,定义了一组多个连接共享的密码安全参数。定义会话的目的主要是避免为每次建立连接而进行复杂的密码参数协商过程
任何一对通信实体(如客户和服务器上的HTTP应用)之间可以有多条安全连接,理论上也允许一对实体之间同时有多个会话,实际上很少出现
- 每个会话有多种状态,一旦会话建立,就进入当前操作(发送和接收)状态。在握手协议执行期间,会进入读(接收)挂起状态和写(发送)挂起状态。握手完成,挂起状态又回到当前操作状态
SSL连接状态参数:
SSL会话状态参数:
2.2.1 SSL记录协议
记录协议在SSL握手协议完成客户端和服务器之间的握手过程后使用,即客户端和服务器完成双方的身份鉴别并确定安全信息交换使用的算法后执行。作服务器托管网用是负责将用户数据进行加密传输。
- 保密性:使用握手协议得到的传统加密共享密钥来加密SSL载荷来实现保密性
- 完整性:使用握手协议得到的MAC共享密钥对SSL载荷进行消息完整性检验
报文格式:
记录协议对应用数据的处理过程:
操作:
- 第一步,分段
- 上层消息的数据被分片成214字节大小的块,或者更小
- 第二步,压缩(可选)
- 必须是无损压缩,如果数据增加的话,则增加部分的长度不超过1024字节
- 第三步,MAC计算
- hash(MAC_write_secrte||pad_1||seq_mum||SSLCompressed.type||SSLCompressed.length||SSLCompressed.fragment)
- (1)||:表示串接。
- (2)MAC_write_secrte:共有的密钥。
- (3)Hash:散列算法;
MD5
或者SHA-1
。 - (4)pad_1:若是使用MD5,则为0x36(00110110)字节重复48次的384位分片,若是用SHA-1,则为0x36重复40次的320位分片。
- (5)pad_2:若是使用MD5,则为0x5C(01010110)字节重复48次的384位分片,若是用SHA-1,则为0x36重复40次的320位分片。
- (6)seq_mum:这个消息的序列号码。
- (7)SSLCompressed.type:用来处理这个分片的上层协议。
- (8)SSLCompressed.length:分片经过压缩过后的长度。
- (9)SSLCompressed.fragment:经过压缩后的分片(假如没有经过压缩这个步骤,则代表明文分片)。
- hash(MAC_write_secrte||pad_1||seq_mum||SSLCompressed.type||SSLCompressed.length||SSLCompressed.fragment)
- 第四步,加密
- 将压缩消息和MAC用对称算法加密。加密增加的长度不超过1024字节。
- 将压缩消息和MAC用对称算法加密。加密增加的长度不超过1024字节。
说明:
- 如果是流密码算法,则不需要填充,MAC在加密之前计算,然后将MAC和明文或压缩后的明文一起被加密。
- 对分组加密而言,填充应在MAC之后、加密之前进行。填充的格式是一定长度的填充字节后跟1字节的填充长度。
SSL采用的是链式加密(数字信封)方法:采用对称加密算法加密消息(SSL记录协议),用公开密码算法交换对称加密算法的对称密钥(SSL握手协议)
2.2.2 SSL密码变更规格协议
协议由一个仅包含1字节且值为1的消息组成,使得连接从挂起状态改变到当前状态,用于更新此连接使用的密码组
Q:为什么不作为其它协议(如握手协议)的一条报文而要独立成一个协议?
A:为了保障SSL传输过程的安全性,SSL协议要求客户端或服务器端每隔一段时间必须改变其加解密参数。当某一方要改变其加解密参数时,就发送一个简单的消息通知对方下一个要传送的数据将采用新的加解密参数,也就是要求对方改变原来的安全参数。因此,无论是从功能上还是从可扩展性来讲,将其独立出来,而不是做为握手协议的一部分更合适。
2.2.3 Alert协议
当客户端和服务器发现错误时,需要通过告警协议向对方发送一个告警消息
- 同应用数据一样,SSL告警协议报文同样交由SSL记录协议进行压缩和加密处理后发送
协议格式:
- 第1个字节表示告警类型:值1表示告警,值2表示致命错误。如果是致命错误,则SSL立即关闭SSL连接,而会话中的其它连接将继续进行,但不会再在此会话中建立新连接
- 第2个字节包含指定告警信息的代码
2.2.4 握手协议
SSL握手协议是客户端和服务器用SSL连接通信时使用的第一个子协议,在开始传输上层应用数据之前使用。
- 该协议允许服务器和客户端相互验证,协商加密和MAC算法以及加密密钥,用来保护在SSL记录协议中发送的数据
客户端与服务器之间建立逻辑连接的初始交换过程包括四个阶段
- 第一阶段:建立安全功能
- 客户端将自己支持的算法列表(密钥组)、用于生成密钥的随机数和压缩方法列表一起发送给服务器
- 服务器从列表中选择加密算法,压缩方法发给客户端
client_hello
- 版本:客户端支持最高版本的SSL版本
- 随机数:32位时间戳+28字节随机数
- 会话标志:
非0
:更新参数/为当前会话创立新连接;0
:为新会话创立新连接 - 密码组:按优先级降序排列的密码算法列表(含密钥交换方法和密码说明)
- 压缩方法:客户端支持的压缩方法列表
server_hello
- 版本:客户端支持的最高版本的SSL版本号和服务器端支持的最低版本的SSL版本号
- 随机数:32位时间戳+28字节随机数
- 会话标志:
非0
(客户端):相同值;0
(客户端):新会话的值 - 密码组:从密码算法列表中选择出的密码组
- 压缩方法:从压缩方法列表选出的压缩方法
密钥交换方法:
- RSA:用接收方RSA公钥加密的密钥,必须拥有接收者公钥的公钥证书
- 固定Diffie-Hellman:签证机构签发公钥证书,证书中包含D-H公钥参数
- 瞬时Diffie-Hellman:用发送者私钥签名D-H公钥交换过程
- 匿名Diffie-Hellman:使用D-H公钥不需要认证
- Fortzza
密码规格说明(CiperSpec):
对称加密算法、MAC算法、密码类型、可否出口、散列长度、密钥材料、IV大小
- 第二阶段:服务器认证和密钥交换
- 服务器将自己公钥的证书发给客户端,密钥交换消息、证书请求,和服务器完成消息发送给客户端
- 证书和密钥交换消息
- 不需要证书:匿名Diffie-Hellman
- 需要密钥交换消息:瞬时Diffie-Hellman、匿名Diffie-Hellman、Fortzza、RSA密钥交换(仅使用签名)
- 不需要密钥交换消息:固定Diffie-Hellman
- 内容:hash ( ClientHello.random || ServerHello.random || ServerParams )
- 证书请求
- 包含两个参数:证书类型和签证机构
- 证书类型:公钥算法和用途
- 签证机构:可接受的签证机构名字表
服务器完成消息:表明服务器的HELLO和相关消息结束了。
- 第三阶段:客户端认证和密钥交换
- 客户端验证服务器证书并检查有效,告知服务器自己的证书,无证书情况下,发送无证书警报
- 客户端发送密钥交换信息,提供对自己证书的验证消息
- RSA:生成预备主密钥,用服务器公钥证书中的密钥交换信息中的公钥加密
证书验证消息:
Certificateverify.signature.md5_hash=
MD5(master_secret || pad_2 || MD5(handshake_messages || master_secret || pad_1));
Certificateverify.signature.sha_hash=
SHA(master_secret || pad_2 || SHA (handshake_messages || master_secret || pad_1)) ;
- Master_secrect:主密钥
- Handshake_messgaes:握手消息,指所有发送的握手协议消息或接收到的从Client_hello消息开始不包括此消息的所有消息
- Pad_1、pad_2:填充值
- 第四阶段:完成
- 客户端发送改变密码规范消息,新的完成消息finished。
- 服务器发送改变密码规范消息,新的完成消息finished。
此消息不是握手协议的一部分,而是使用修改密码规范协议发送的。
MD5(master_secret || pad2 || MD5(handshake_messages || Sender || master_secret || pad1))
SHA(master_secret || pad2 || SHA(handshake_messages || Sender || master_secret || pad1))
- sender:表示发送者为客户端
- Handshake_messgaes:不包括此消息的所有握手消息
- Pad1、pad2:填充值
至此,握手过程完成,客户端和服务器可以开始交换应用层数据了。
下面我们用一个形象的比喻来说明上述过程。假设 A与B 通信,A是SSL客户端,B是SSL服务器,加密后的消息放在方括号[ ]里,以突出与明文消息的区别。双方的处理动作在小括号()中说明。过程如下:
A:我想和你进行安全通话,我这里的对称加密算法有DES和RC5,密钥交换算法有RSA和DH,散列算法有MD5和SHA-1。
B:我们用DES——RSA——SHA-1这对组合好了。
这是我的证书,里面有我的名字和公钥,你拿去验证一下我的身份(把证书发给A)。
目前没有别的可说的了。
A:(查看证书上B的名字是否无误,并通过自己保存的CA证书验证了B提供的证书的真实性,如果其中一项有误,就发出告警并断开连接,这一步保证了B的公钥的真实性)
(产生一份秘密消息,这份秘密消息处理后将用作加密密钥,加密初始化向量IV和HMAC的密钥。将这份秘密消息,即per_master_secret(预主密钥),用B的公钥加密,封装成消息ClientKeyExchange。由于用了B的公钥,保证了第三方无法窃听)
我生成了一份秘密消息,并用你的公钥加密了,给你(把ClientKeyExchange发给B)。
注意,下面我就要用加密的办法给你发消息了!
(将秘密消息进行处理,生成加密密钥,加密初始化向量和HMAC的密钥)
[我说完了]
B:(用自己的私钥将 ClientKeyExchange 中的秘密消息解密出来,然后将秘密消息进行处理,生成加密密钥,加密初始化向量IV和HMAC的密钥,这时双方已经安全地协商出一套加密办法了)
注意,我也要开始用加密的办法给你发消息了!
[我说完了]
A:[我的秘密是……]
B:[其他人不会听到的……]
SSL握手过程实例分析
2.2.5 密钥生成
共享主密钥是利用安全密钥交换为此会话建立的一个一次性48字节的值,生成过程分两步:
- 第一步交换预备主密钥(握手协议的“阶段3”)
- 第二步双方计算主密钥。
两类密钥交换算法:
- RSA,客户产生一个48字节的pre_master_secret,然后用服务器的公钥加密传递给服务器
- Diffie-Hellman,双方协商得到的密钥被用作pre_master_secret
对于各种密钥交换算法,从pre_master_secret计算得到master_secret,然后从内存中删除
计算主密钥:
客户和服务器使用相同的算法和参数计算出对称加密密钥(主密钥)和参数:
生成密码参数:
- 需要主密钥生成密钥分组
- 4个用于数据保护的会话密钥:
- 服务器写加密密钥(Esc)、服务器写MAC密钥(Msc):分别用于服务器发出数据的加密和消息验证码计算。
- 客户端写加密密钥(Ecs)、客户端写MAC密钥(Mcs):分别用于客户端发出数据的加密和消息验证码计算。
计算过程步骤如下:
- 由预主密钥、客户端随机数和服务器端随机数共同生成主密钥。
- 由主密钥、客户端随机数和服务器端随机数共
同生成密钥分组。 - 把密钥分组分成6块,按照所需的密钥长度依次
截取得到Mcs、Msc、Ecs、Esc、lVcs
(客户端初始向量)、和IVsc
(服务器初始向量)。
多选题:以下关于SSL握手协议的说法正确的是()
A.SSL主密钥的生成只与预主密钥有关
B.SSL密钥参数的生成与主密钥、客户端随机数和服务器随机数有关
C.SSL握手过程中,客户端随机数和服务器端随机数以明文进行传输
D.SSL预主密钥在握手第三阶段完成时完成交互
答案:BCD
2.3 SSL实现的安全服务
SSL保障的安全属性:
- 机密性:SSL 客户机和服务器之间传送加密数据。
- 完整性:SSL 可避免服务器和客户机之间的信息被破坏。
- 认证性(不可否认性):SSL 握手时要求交换证书,通过验证证书来保证对方身份的合法性。
2.4 SSL的安全性分析
SSL协议的安全性隐患:
1)预主密钥→master_secret→SSL会话密钥
2)能否保证随机数质量也是SSL的安全隐患。
3)有可能遭受中间人攻击。
4)利用SSL的攻击无法被IDS检测和FW过滤到。
5)Web服务器使用SSL时,吞吐量会显著下降。
6)不能保证Web浏览器和服务器自身安全。
1)主密钥生成过程中,由于客户端随机数和服务器随机数是在主密钥生成之前生成的,是明文传输,只要攻击者得到了预主密钥,就能算法主密钥,从而得到SSL的会话密钥(主密钥)
3)用证书来进行身份认证,有可能进行假冒服务攻击(攻击者窃取有效证书和对应的私钥,欺骗客户端)
4)加密通信对现有的安全检测系统,如基于网络的入侵检测系统和防火墙无法对流量进行检测
5)加解密比较耗时
增强SSL安全性:
- 增强master_secret的保密性
- 预主密钥的口令加密方法和硬件加密方法。
- 提高随机数的质量
- 用硬件随机数发生器产生的随机数作为产生随机数的软件方法PRNG的种子,进行高强度处理。
- 提高证书CA的可靠性
- 在服务器认证阶段,CA控制所有证书的颁发和有效性判断。
3. TLS
IETF在SSL3.0版本的基础上制定了SSL的互联网标准版本,称为“传输层安全” (Transport Layer Security,TLS),使SSL更安全、协议规范更精确和完善。2011年发布的RFC 6167中建议禁用SSL 2.0, 2015年发布的RFC 7568中建议禁用SSL 3.0
- TLS版本:TLS 1.0 (RFC 2246, 1999),TLS 1.1 (RFC4346, 2006),TLS 1.2 (RFC 5246, 2008),TLS 1.3 (RFC 8446, 2018)。其中,TLS 1.0对应SSL的3.0版
- 名称:SSL, SSL/TLS
3.1 TLS与SSL的差异
- 版本号
- TLS 1.0 的主版本为3, 次版本为1,而与之对应的SSL 3.0的主版本为3,次版本为0。TLS 1.1的主版本为3,次版本为2
- 消息认证码
- TLS的MAC与SSL3.0的MAC有两点不同:TLS使用RFC2104中定义的HMAC算法;TLS使用称为“PRF”的伪随机函数
- 告警码
- 除no_certificate外,TLS继承了SSL3.0中定义的所有告警码。另外,还定义了新的告警码
- 密码套件
- TLS和SSL3.0存在细小差别,即TLS不支持Fortezza密钥交换、加密算法,而SSL3.0是支持的
- 客户端证书类型
- 在CertificateRequest消息中,TLS支持SSL3.0中定义的rsa_sign, dss_sign, rsa_fixed_dh和dss_fixed_dh证书,但不支持SSL 3.0支持的rsa_ephemeral_dh, dss_ephemeral和fortezza_kea证书
- CertificateVerify消息
- TLS在CertificateVerify消息中计算MD5和SHA-1散列码时,计算的输入与SSL 3.0有少许差别,但安全性相当
- 仅对handshake_message进行MD5或SHA-1散列值计算,而在SSL 3.0中散列值计算还包括主密钥和填充,但这些额外信息似乎并没有增加安全性
- Finished消息
- TLS在Finished消息中计算MD5和SHA-1散列码时,计算的输入与SSL 3.0有少许差别,但安全性相当
- 密码计算
- TLS和SSL 3.0在计算主密钥值(master secret)时采用的方式不同,过程如下:
- master_secret=PRF (pre_master_secret, “master secret”,
ClientHello.random || ServerHello.random)
上述算法被连续执行,直到完全产生48字节的伪随机数输出为止。对密钥数据块(MAC密钥、会话加密密钥和初始向量Ⅳ)的计算则按下面的定义执行:
key_block =PRF(master_secret, “key_expansion”, SecurityParameters.server_random || SecurityParameters.client_random)
上述算法同样被连续执行,直到产生足够的输出为止。同SSL3.0一样,密钥块key_block也是主密钥master_secret和客户端与服务器随机数的函数,但实际的计算方法有所不同。
- 填充
- 在SSL中,填充后的数据长度正好是分组加密算法中分组长度的最小整数倍。而TLS填充后的数据长度可以是分组长度的任意整数倍(但填充最大长度为255字节)。
- 例如,如果明文(如果使用了压缩算法则是压缩后的明文)加MAC再加上表示填充长度的1个字节共79字节,则填充长度按字节计算时可以是1、9、17、25等,直到249。这种可变填充长度可以防止基于对报文长度进行分析的攻击
3.2 TLS 1.3
安全上的考虑:
- TLS广泛的应用使得其成为了攻击者的“众矢之的”,这些攻击或利用TLS设计本身存在的不足(如幸运十三攻击、三次握手攻击、跨协议攻击等),或利用TLS所用密码原语本身的缺陷(如RC4加密、RSA-PKCS#1v1.5加密等),或利用TLS实现库中的漏洞(如心脏出血攻击等)
性能上的考虑:
- 近年来,对网络上所有通信使用加密传输已经成为了主流趋势,很多Web应用都开始强制使用基于TLS的HTTPS,而不是采用明文传输的HTTP。这对保护我们在网络上传输的数据避免被窃听和注入攻击有积极影响,但是不足之处在于交互双方必须运行复杂的TLS握手协议才能开始传输信息。
禁止使用RSA密钥交换算法:
- “RSA密钥交换”和基于Diffie-Hellman协议的匿名Diffie-Hellman交换和瞬时Diffie-Hellman交换,这两种模式都可以让客户端和服务器得到共享秘钥,但是RSA模式有一个严重的缺陷:它不满足前向保密(forward secret),以及“百万消息攻击”等攻击
- 仅保留瞬时Diffie-Hellman作为唯一的秘钥交换机制
减少不安全的Diffie-Hellman参数选项:
- 选择Diffie-Hellman参数时,提供太多的选项会导致选择出错误的选项。
删除不安全的认证加密方法:
- CBC 模式和填充之间的交互也是 SSL3.0和一些 TLS 实现中出现的著名的POODLE 漏洞的成因。TLS 1.3 中允许的唯一认证加密方法是AEAD(Authenticated Encryption with Additional Data),它将机密性和完整性整合到一个无缝操作中
浅谈“POODLE信息泄露漏洞”
禁止一些安全性较弱的密码原语
- TLS 1.3已删除所有可能存在问题的密码组件和密码模式,包括CBC 模式密码或不安全的流式密码,如 RC4。建议用SHA-2,不建议使用安全性较弱的MD5和SHA-1
对整个握手过程签名
- 在TLS 1.2及更早版本中,服务器的签名仅涵盖部分握手协议报文,其它使用对称MAC来确保握手未被篡改。这种疏忽导致了许多严重的安全漏洞,如FREAK、LogJam攻击等。FREAK攻击也称为降级攻击
- TLS 1.3服务器对整个握手记录进行签名,包括密钥协商,避免三次握手攻击。此外,还实现了握手协议和记录协议的密钥分离。
性能上的改进
- SSL:“2-RTT (Round Trip Time)”,200ms
TLS1.3舍弃了RSA的密钥协商过程,然后基于ECDH密钥协商算法(EC即椭圆曲线,DH是指“Diffie-Hellman”)优化了整个过程,改为“1-RTT
”
TLS 1.3除了对新建连接过程进行优化之外,对连接恢复过程也进行了优化,做到了零次往返(0-RTT
)
4. SSL/TLS VPN
IPsec VPN也有一些不足之处:
- 无法实现基于用户的授权
- 可能泄露内部网络结构
利用基于SSL/TLS的VPN可以很好解决远程终端访问内部网络时存在的上述问题(SSL/TLS VPN简称为SSL VPN)
实现过程:
应用场景:Web代理、端口映射、IP连接
- 与单纯SSL/TLS只对某些TCP应用(如HTTPS)进行保护相比,SSL/TLS VPN利用TCP以及SSL对TCP会话的保护,可实现对基于TCP、UDP、IP的应用的保护
- 与IPsec VPN相比,SSL/TLS VPN可以提供更细粒度的访问控制
- 实际应用中,IPsec VPN与SSL VPN的应用场景是不一样的。
- IPsec VPN是在网络层实现加密通信,故IPsec VPN主要应用于将远程终端或分支机构网络与机构内部网络安全连接起来的场合
- SSL VPN则主要用于远程终端通过Web浏览器访问内部网络中的应用服务器(如Web服务器、电子邮件服务器等)这一场合
OK,以上就是本期知识点“传输层安全”的知识啦~~ ,感谢友友们的阅读。后续还会继续更新,欢迎持续关注哟~
如果有错误❌,欢迎批评指正呀~让我们一起相互进步
如果觉得收获满满,可以点点赞支持一下哟~
❗ 转载请注明出处
作者:HinsCoder
博客链接: 作者博客主页
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net