热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

TLS协议分析(四)handshake协议概览

5.handshake协议handshakeprotocol重要而繁琐。TLS1.3对握手做了大修改,下面先讲TLS1.2,讲完再介绍一下分析TLS

5. handshake 协议

handshake protocol重要而繁琐。

TLS 1.3对握手做了大修改,下面先讲TLS 1.2,讲完再介绍一下分析TLS 1.3.


5.1.handshake的总体流程

handshake protocol用于产生给record protocol使用的SecurityParameters。
在handshake中:


  • 客户端和服务器端协商TLS协议版本号和一个CipherSuite,
  • 认证对端的身份(可选,一般如https是客户端认证服务器端的身份),
  • 并且使用密钥协商算法生成共享的master secret。

步骤如下:


  • 交换Hello消息,协商出算法,交换random值,检查session resumption.
  • 交换必要的密码学参数,来允许client和server协商出premaster secret。
  • 交换证书和密码学参数,让client和server做认证,证明自己的身份。
  • 从premaster secret和交换的random值 ,生成出master secret。
  • 把SecerityParameters提供被record层。
  • 允许client和server确认对端得出了相同的SecurityParameters,并且握手过程的数据没有被攻击者篡改。

Handshake的结果是在双方建立相同的Session,Session 包含下列字段:


  1. session identifier
    session id,用来唯一标识一个session,在session 恢复的时候,也要用到
  2. peer certificate
    对端的 X509v3 格式证书. 如果不需要认证对端的身份,就为空。
  3. compression method
    压缩算法,一般被禁用
  4. cipher spec
    CipherSuite,如上文介绍,包含: 用于生成key的pseudorandom function (PRF) , 块加密算法例如AES, MAC算法 (例如 HMAC-SHA256). 还包括一个 mac_length字段,在后文的we握手协议介绍
  5. master secret
    48字节的,client和server共享密钥。
  6. is resumable
    一个标志位,用来标识当前session是否能被恢复。

以上字段,随后被用于生成 record层的SecurityParameters,多个连接可以通过握手协议的session恢复功能来复用同一个session。

握手协议使用 非对称加密/密钥协商/数字签名 3类算法,
因此要求读者对这3类算法概念清晰,能准确区分。
在此澄清一下,:
非对称的算法分为3类:
,


  • 非对称加密,有:RSAES-PKCS1-v1_5,RSAES-OAEP ,Rabin-Williams-OAEP, Rabin-Williams-PKCS1-v1_5等
  • 非对称密钥协商,有:DH,DHE,ECDH,ECDHE 等
  • 非对称数字签名:RSASSA-PKCS1-v1_5,RSASSA-PSS,ECDSA,DSA,ED25519 等

另外,非对称加密算法,可以当作密钥协商算法来用,所以 RSAES-PKCS1-v1_5,RSAES-OAEP 也可以当作密钥协商算法来用



插播一段 RSA:

RSA的实际工程应用,要遵循PKCS#1 标准,见 https://www.ietf.org/rfc/rfc3447

其中的 RSAES-PKCS1-v1_5 和 RSASSA-PKCS1-v1_5 是使用RSA算法的两种不同scheme(体制)。
RSAES表示 RSA Encryption schemes,即非对称加密,
RSAES有:RSAES-OAEP,RSAES-PKCS1-v1_5两种,其中RSAES-OAEP更新更安全

RSASSA表示 Signature schemes with appendix,即appendix模式(appendix和recovery的区别请参看密码学教材)的非对称数字签名算法。
RSASSA有: RSASSA-PSS, RSASSA-PKCS1-v1_5 两种, 其中RSASSA-PSS更新更安全

RSA还有一个缺陷,就是很容易被时间侧通道攻击,所以现在的RSA实现都要加 blinding ,后文有介绍。

可以看到,RSA是一种很特殊的算法,既可以当非对称加密算法使用,又可以当非对称数字签名使用。这一点很有迷惑性,其实很多用RSA的人都分不清自己用的是RSA的哪种模式。

相比之下,ECC(椭圆曲线)这一块的算法就很清晰,ECDSA只能用作数字签名,ECDH只能用作密钥交换。

分清楚 RSAES-PKCS1-v1_5 和 RSASSA-PKCS1-v1_5 有什么用涅?

PKCS#1规范解释:


A generally good cryptographic practice is to employ a given RSA
key pair in only one scheme. This avoids the risk that
vulnerability in one scheme may compromise the security of the
other, and may be essential to maintain provable security.


FIPS PUB 186-3 美国标准规定:


An RSA key pair used for digital signatures shall only be used for one
digital signature scheme (e.g., ANS X9.31, RSASSA-PKCS1 v1.5 or
RSASSA-PSS; see Sections 5.4 and 5.5). In addition, an RSA digital
signature key pair shall not be used for other purposes (e.g., key
establishment).


一对密钥只做一个用途,要么用作非对称加解密,要么用作签名验证,别混着用!
一对密钥只做一个用途,要么用作非对称加解密,要么用作签名验证,别混着用!
一对密钥只做一个用途,要么用作非对称加解密,要么用作签名验证,别混着用!

这个要求,决定了一个协议的 PFS(前向安全性),在斯诺登曝光NSA的“今日捕获,明日破解”政策后,越发重要

https://news.ycombinator.com/item?id=5942534

http://news.netcraft.com/archives/2013/06/25/ssl-intercepted-today-decrypted-tomorrow.html

https://lwn.net/Articles/572926/

https://www.eff.org/deeplinks/2014/04/why-web-needs-perfect-forward-secrecy

http://www.wired.com/2013/10/lavabit_unsealed

PFS反映到密钥协商过程中,就是:


  • 不要使用RSA做密钥协商,一定只用RSA做数字签名
  • 不要把ECDH的公钥固定内置在客户端做密钥协商

后文可以看到这一原则在 TLS 1.3, QUIC,Apple的iMessage等协议中一再贯彻。

非对称RSA/ECC这个话题比较大了,后面有空再写文章吧,读者可以先看一下参考资料,里面有清晰的介绍。

插播结束,继续TLS。



由于设计的时候,就要考虑兼容性,而且实际历史悠久,所以TLS协议90年代曾经使用的一些算法,现在已经被破解了,例如有的被发现漏洞(rc4),有的密钥长度过短(例如曾经美帝有出口限制,限制RSA 在512比特以下,对称加密密钥限制40比特以下,后来2005年限制被取消),但是考虑到兼容,现在的TLS实现中,还是包含了这种已经被破解的老算法的代码。这样,如果攻击者可以干扰握手过程,诱使client和server使用这种已经被破解的算法,就会威胁TLS协议的安全,这被称为“降级攻击”。

为了在握手协议解决降级攻击的问题,TLS协议规定:client发送ClientHello消息,server必须回复ServerHello消息,否则就是fatal error,当成连接失败处理。ClientHello和ServerHello消息用于建立client和server之间的安全增强能力,ClientHello和ServerHello消息建立如下属性:


  • Protocol Version
  • Session ID
  • Cipher Suite
  • Compression Method.

另外,产生并交换两个random值 ClientHello.random 和 ServerHello.random

密钥协商使用四条: server的Certificate,ServerKeyExchange,client的Certificate,ClientKeyExchange 。TLS规定以后如果要新增密钥协商方法,可以订制这4条消息的数据格式,并且指定这4条消息的使用方法。密钥协商得出的共享密钥必须足够长,当前定义的密钥协商算法生成的密钥长度必须大于46字节

在hello消息之后,server会把自己的证书在一条Certificate消息里面发给客户端(如果需要做服务器端认证的话,例如https)。 并且,如果需要的话,server会发送一条ServerKeyExchange消息,(例如如果服务器的证书只用做签名,不用做密钥交换,或者服务器没有证书)。client对server的认证完成后,server可以要求client发送client的证书,如果这是协商出来的CipherSuite允许的。下一步,server会发送ServerHelloDone消息,表示握手的hello消息部分已经结束。然后server会等待一个client的响应。如果server已经发过了CertificateRequest消息,client必须发送Certificate消息。然后发送ClientKeyExchange消息,并且这条消息的内容取决于ClientHello和ServerHello消息协商的算法。如果client发送了有签名能力的证书,就显式发送一个经过数字签名的CertificateVerify消息,来证明自己拥有证书私钥。

然后,client发送一个ChangeCipherSpec消息,并且client拷贝待定的Cipher Spec到当前的Cipher Spec。然后client立即用新算法+新key+新密钥 发送Finished消息。收到后,server发送自己的ChangeCipherSpec消息,作为响应,并且拷贝待定的Cipher Spec到当前的Cipher Spec。此时,握手就完成了,client和server可以开始交换应用层数据(如下图所示)。应用层数据不得在握手完成前发送。

引用一个来自网络的图片:
图片

Client ServerClientHello -------->ServerHelloCertificate*ServerKeyExchange*CertificateRequest*<-------- ServerHelloDone
Certificate*
ClientKeyExchange
CertificateVerify*
[ChangeCipherSpec]
Finished -------->[ChangeCipherSpec]<-------- Finished
Application Data <-------> Application DataFigure 1. Message flow for a full handshake* 表示可选的消息&#xff0c;或者根据上下文在某些情况下会发送的消息。Indicates optional or situation-dependent messages that are not
always sent.

注&#xff1a;为了帮助解决管道阻塞的问题&#xff0c;ChangeCipherSpec是一个独立的TLS protocol content type&#xff0c;并不是一个握手消息。

TLS的完整握手过程&#xff0c;要进行RSA/ECDH/ECDSA等非对称计算&#xff0c;非对称计算是很慢的。关于非对称的性能&#xff1a;
例如在2015年的服务器cpu&#xff1a; Intel® Xeon® CPU E3-1230 V2 &#64; 3.30GHz 上&#xff0c;
使用如下命令测试&#xff1a;

openssl speed rsa2048
openssl speed ecdsap256
openssl speed ecdhp256
openssl speed aes-128-cbc
openssl speed -evp aes-128-cbc

结果如下表&#xff1a;


算法性能性能
RSA-2048私钥运算 723.7 次/秒公钥运算 23505.8 次/秒
256 bit ecdsa (nistp256)签名 8628.4 次/秒验证 2217.0 次/秒
256 bit ecdh (nistp256)ECDH协商 2807.8 次/秒
aes-128-cbc加密 121531.39 K/秒
aes-128-cbc 使用aesni硬件加速加密 683682.13 K/秒

注&#xff1a;非对称的单位是 次/秒&#xff0c;这是由于非对称一般只用于处理一个block&#xff0c;
对称的单位是 K/秒&#xff0c;因为对称一般用于处理大量数据流&#xff0c;所以单位和流量一样。
可以给非对称的 次/秒 乘以 block size &#xff0c;就可以和对称做比较了。例如rsa-2048&#xff0c;723.7*2048/8/1024&#61;185.2672 K/秒 &#xff0c;
RSA-2048 私钥运算性能 是aes-128-cbc 的 1.5/1000。是aesni的 2.6/10000

如上&#xff0c;性能数据惨不忍睹&#xff0c; 简直不能忍&#xff01;&#xff01;&#xff01;

有鉴于此&#xff0c;TLS从设计之初&#xff0c;就采用了万能手段—加cache&#xff0c;有2种cache手段&#xff1a;session id&#xff0c;和session ticket。把握手的结果直接cache起来&#xff0c;绕过握手运算。

当client和server决定恢复一个之前的session&#xff0c;或复用一个已有的session时(可以不用协商一个新的SecurityParameters)&#xff0c;消息流程如下&#xff1a;

客户端使用要被恢复的session&#xff0c;发送一个ClientHello&#xff0c;把Session ID包含在其中。server在自己的session cache中&#xff0c;查找客户端发来的Session ID&#xff0c;如果找到&#xff0c;sever把找到的session 状态恢复到当前连接&#xff0c;然后发送一个ServerHello&#xff0c;在ServerHello中把Session ID带回去。然后&#xff0c;client和server都必须ChangeCipherSpec消息&#xff0c;并紧跟着发送Finished消息。这几步完成后&#xff0c;client和server 开始交换应用层数据&#xff08;如下图所示&#xff09;。如果server在session cache中没有找到Session ID&#xff0c;那server就生成一个新的session ID在ServerHello里给客户端&#xff0c;并且client和server进行完整的握手。

流程图如下&#xff1a;

Client ServerClientHello -------->ServerHello[ChangeCipherSpec]<-------- Finished
[ChangeCipherSpec]
Finished -------->
Application Data <-------> Application DataFigure 2. Message flow for an abbreviated handshake

5.2. handshake 协议外层结构

从消息格式来看&#xff0c;TLS Handshake Protocol 在 TLS Record Protocol 的上层. 这个协议用于协商一个session的安全参数。 Handshake 消息&#xff08;例如ClientHello&#xff0c;ServerHello等&#xff09; 被包装进 TLSPlaintext结构里面&#xff0c;传入TLS record层&#xff0c;根据当前session 状态做处理&#xff0c;然后传输。

如下&#xff1a;

enum {hello_request(0), client_hello(1), server_hello(2),certificate(11), server_key_exchange (12),certificate_request(13), server_hello_done(14),certificate_verify(15), client_key_exchange(16),finished(20), (255)
} HandshakeType;struct {HandshakeType msg_type; /* handshake type */uint24 length; /* bytes in message */select (HandshakeType) { case hello_request: HelloRequest; case client_hello: ClientHello; case server_hello: ServerHello;case certificate: Certificate; case server_key_exchange: ServerKeyExchange;case certificate_request: CertificateRequest;case server_hello_done: ServerHelloDone;case certificate_verify: CertificateVerify;case client_key_exchange: ClientKeyExchange;case finished: Finished;case session_ticket: NewSessionTicket; /* NEW */} body;
} Handshake;

TLS协议规定&#xff0c;handshake 协议的消息必须按照规定的顺序发&#xff0c;收到不按顺序来的消息&#xff0c;当成fatal error处理。也就是说&#xff0c;TLS协议可以当成状态机来建模编码。

下面按照消息发送必须遵循的顺序&#xff0c;逐个解释每一条握手消息。

handshake协议的外层字段&#xff0c;见这个抓包&#xff1a;

图片


5.3. handshake — ClientHello&#xff0c;ServerHello&#xff0c;HelloRequest

Hello消息有3个&#xff1a;ClientHello, ServerHello&#xff0c;HellloRequest
逐个说明&#xff1a;


5.3.1 Client Hello

当客户端第一次连接到服务器时&#xff0c;第一条message必须发送ClientHello。
另外&#xff0c;rfc里规定&#xff0c;如果客户端和服务器支持重协商&#xff0c;在客户端收到服务器发来的HelloRequest后&#xff0c;也可以回一条ClientHello&#xff0c;在一条已经建立的连接上开始重协商。(重协商是个很少用到的特性。)

消息结构&#xff1a;

struct {uint32 gmt_unix_time;opaque random_bytes[28];
} Random;opaque SessionID<0..32>;uint8 CipherSuite[2];enum { null(0), (255) } CompressionMethod;struct {ProtocolVersion client_version;Random random;SessionID session_id;CipherSuite cipher_suites<2..2^16-2>;CompressionMethod compression_methods<1..2^8-1>;select (extensions_present) { case false: struct {}; case true:Extension extensions<0..2^16-1>;};
} ClientHello;

Random 其中&#xff1a;
gmt_unix_time 是 unix epoch时间戳。
random_bytes 是 28字节的&#xff0c;用密码学安全随机数生成器 生成出来的随机数。



密码学安全的随机数生成&#xff0c;这是个很大的话题&#xff0c;也是一个大陷阱&#xff0c;目前最好的做法就是用 /dev/urandom&#xff0c;或者openssl库的 RAND_bytes()

历史上&#xff0c;恰好就在SSL的random_bytes这个字段&#xff0c;NetScape浏览器早期版本被爆出过随机数生成器漏洞。
被爆菊的随机数生成器使用 pid &#43; 时间戳 来初始化一个seed&#xff0c;并用MD5(seed)得出结果。
见 http://www.cs.berkeley.edu/~daw/papers/ddj-netscape.html&#xff0c;
建议读者检查一下自己的随机数生成器。




client_version
客户端支持的最高版本号。
random
客户端生成的random。

ClientHello.session_id 唯一标识一个session&#xff0c;用来做session cache。如果为空&#xff0c;表示不做复用&#xff0c;要求服务器生成新的session。
session_id的来源有&#xff1a;


  1. 之前的协商好的连接的session_id
  2. 当前连接的session_id
  3. 当前也在使用中的另一条连接的session_id

其中第三种允许不做重新握手&#xff0c;就同时建立多条独立的安全连接。这些独立的连接可能顺序创建&#xff0c;也可以同时创建。一个SessionID当握手协商的Finished消息完成后&#xff0c;就合法可用了。存活直到太旧被移除&#xff0c;或者session 关联的某个连接发生fatal error。SessionID的内容由服务器端生成。

注&#xff1a;由于SessionID的传输是不加密&#xff0c;不做MAC保护的&#xff0c;服务器不允许把私密信息发在里面&#xff0c;不能允许伪造的SessionID在服务器造成安全问题。&#xff08;握手过程中的数据&#xff0c;整体是受Finished消息的保护的&#xff09;

ClientHello.cipher_suites字段&#xff0c;包含了客户端支持的CipherSuite的列表&#xff0c;按照客户端希望的优先级排序&#xff0c;每个CipherSuite有2个字节&#xff0c;每个CipherSuite由&#xff1a;一个密钥交换算法&#xff0c;一个大量数据加密算法(需要制定key length参数)&#xff0c;一个MAC算法&#xff0c;一个PRF 构成。服务器会从客户端发过来的列表中选择一个&#xff1b;如果没有可以接受的选择&#xff0c;就返回一个 handshake failure 的 alert&#xff0c;并关闭连接。如果列表包含服务器不认识&#xff0c;不支持&#xff0c;或者禁用的CipherSuite&#xff0c;服务器必须忽略。
如果SessionID不为空&#xff0c;则cipher_suites里面起码要包含客户端cache的session里面的那个CipherSuite

compression_methods&#xff0c;类似地&#xff0c;ClientHello里面包含压缩算法的列表&#xff0c;按照客户端优先级排序。当然&#xff0c;如前介绍&#xff0c;服务器一般禁用TLS的压缩。

compression_methods 后面可以跟一组扩展(extensions)&#xff0c; extensions都是可选的&#xff0c;比较有用的扩展如&#xff1a; SNI, session ticket&#xff0c;ALPN&#xff0c;OCSP 等&#xff0c;后文介绍。

客户端发送了ClientHello后&#xff0c;服务器端必须回复ServerHello消息&#xff0c;回复其他消息都会导致 fatal error 关闭连接。


5.3.2 Server Hello

当收到客户端发来的ClientHello后&#xff0c;正常处理完后&#xff0c;服务器必须回复ServerHello。

消息结构&#xff1a;

struct {ProtocolVersion server_version;Random random;SessionID session_id;CipherSuite cipher_suite;CompressionMethod compression_method;select (extensions_present) { case false: struct {}; case true:Extension extensions<0..2^16-1>;};
} ServerHello;

server_version
服务器选择 ClientHello.client_version 和 服务器支持的版本号 中的最小的。
random
服务器生成的random&#xff0c;必须确保和客户端生成的random没有关联。
session_id
服务器为本连接分配的SessionID。如果ClientHello.session_id不为空&#xff0c;服务器会在自己的本地做查找。


  • 如果找到了匹配&#xff0c;并且服务器决定复用找到的session建立连接&#xff0c;服务器应该把ClientHello.session_id同样的 session id填入ServerHello.session_id&#xff0c;这表示恢复了一个session&#xff0c;并且双方会立即发送Finished消息。
  • 否则&#xff0c;回复一个和ClientHello.random_id不同的Serverhello.session_id&#xff0c;来标识新session。服务器可以回复一个空的session_id&#xff0c;来告诉客户端这个session不要cache&#xff0c;不能恢复。
    如果一个session 被恢复了&#xff0c;那必须恢复成之前协商的session里面的 CipherSuite。要注意的是&#xff0c;并不要求服务器一定要恢复session&#xff0c; 服务器可以不做恢复。

在实践中&#xff0c;session cache在服务器端要求key-value形式的存储&#xff0c;如果tls服务器不止一台的话&#xff0c;就有一个存储怎么共享的问题&#xff0c;要么存储同步到所有TLS服务器的内存里&#xff0c;要么专门搞服务来支持存储&#xff0c;并使用rpc访问&#xff0c;
无论如何&#xff0c;都是很麻烦的事情&#xff0c;相比之下&#xff0c;后文要介绍的session ticket就简单多了&#xff0c;所以一般优先使用session ticket。


cipher_suite
服务器选定的一个CipherSuite。如果是恢复的session&#xff0c;那就是session里的CipherSuite。
compression_method
跟上面类似。
extensions
扩展列表。要注意的是&#xff0c;ServerHello.extensions 必须是 ClientHello.extensions的子集。


5.3.3 Hello Extensions

The extension 的格式是:

struct {ExtensionType extension_type;opaque extension_data<0..2^16-1>;
} Extension;enum {signature_algorithms(13), (65535)
} ExtensionType;

其中:


  • “extension_type” 标识是哪一个扩展类型。
  • “extension_data” 一坨二进制的buffer&#xff0c;扩展的数据体&#xff0c;各个扩展自己做解析。

extension_type 只能出现一次&#xff0c;ExtensionType之间不指定顺序。

extensions 可能在新连接创建时被发送&#xff0c;也可能在要求session恢复的时候被发送。所以各个extension都需要规定自己再完整握手和session恢复情况下的行为。
这些情况比较琐碎而微妙&#xff0c;具体案例要具体分析。


5.3.4 Hello Request

服务器任何时候都可以发送 HelloRequest 消息。

HelloRequest的意思是&#xff0c;客户端应该开始协商过程。客户端应该在方便的时候发送ClientHello。服务器不应该在客户端刚创建好连接后&#xff0c;就发送HelloRequest&#xff0c;此时应该让客户端发送ClientHello。

客户端收到这个消息后&#xff0c;可以直接忽略这条消息。
服务器发现客户端没有响应HelloRequest后&#xff0c;可以发送fatal error alert。

消息结构&#xff1a;

struct { } HelloRequest;

HelloRequest不包含在握手消息的hash计算范围内。

本文转自微信后台团队,如有侵犯,请联系我们立即删除

OpenIMgithub开源地址&#xff1a;

https://github.com/OpenIMSDK/Open-IM-Server

OpenIM官网 &#xff1a; https://www.rentsoft.cn

OpenIM官方论坛&#xff1a; https://forum.rentsoft.cn/

更多技术文章&#xff1a;

开源OpenIM&#xff1a;高性能、可伸缩、易扩展的即时通讯架构
https://forum.rentsoft.cn/thread/3

【OpenIM原创】简单轻松入门 一文讲解WebRTC实现1对1音视频通信原理
https://forum.rentsoft.cn/thread/4

【OpenIM原创】开源OpenIM&#xff1a;轻量、高效、实时、可靠、低成本的消息模型
https://forum.rentsoft.cn/thread/1


推荐阅读
  • 本文介绍了在rhel5.5操作系统下搭建网关+LAMP+postfix+dhcp的步骤和配置方法。通过配置dhcp自动分配ip、实现外网访问公司网站、内网收发邮件、内网上网以及SNAT转换等功能。详细介绍了安装dhcp和配置相关文件的步骤,并提供了相关的命令和配置示例。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • Servlet多用户登录时HttpSession会话信息覆盖问题的解决方案
    本文讨论了在Servlet多用户登录时可能出现的HttpSession会话信息覆盖问题,并提供了解决方案。通过分析JSESSIONID的作用机制和编码方式,我们可以得出每个HttpSession对象都是通过客户端发送的唯一JSESSIONID来识别的,因此无需担心会话信息被覆盖的问题。需要注意的是,本文讨论的是多个客户端级别上的多用户登录,而非同一个浏览器级别上的多用户登录。 ... [详细]
  • 本文介绍了Windows Vista操作系统中的用户账户保护功能,该功能是为了增强系统的安全性而设计的。通过对Vista测试版的体验,可以看到系统在安全性方面的进步。该功能的引入,为用户的账户安全提供了更好的保障。 ... [详细]
  • JSP内置对象之application的作用范围和获取方式
    本文介绍了JSP内置对象之application的作用时间范围、可以在不同浏览器获取的特点,以及获取application对象的方法。通过示例代码展示了在JSP中设置和在servlet中获取application对象的步骤。对于学习JSP内置对象的读者来说,本文具有一定的参考价值。摘要长度为163字。 ... [详细]
  • RouterOS 5.16软路由安装图解教程
    本文介绍了如何安装RouterOS 5.16软路由系统,包括系统要求、安装步骤和登录方式。同时提供了详细的图解教程,方便读者进行操作。 ... [详细]
  • 如何在php文件中添加图片?
    本文详细解答了如何在php文件中添加图片的问题,包括插入图片的代码、使用PHPword在载入模板中插入图片的方法,以及使用gd库生成不同类型的图像文件的示例。同时还介绍了如何生成一个正方形文件的步骤。希望对大家有所帮助。 ... [详细]
  • MySQL数据库锁机制及其应用(数据库锁的概念)
    本文介绍了MySQL数据库锁机制及其应用。数据库锁是计算机协调多个进程或线程并发访问某一资源的机制,在数据库中,数据是一种供许多用户共享的资源,如何保证数据并发访问的一致性和有效性是数据库必须解决的问题。MySQL的锁机制相对简单,不同的存储引擎支持不同的锁机制,主要包括表级锁、行级锁和页面锁。本文详细介绍了MySQL表级锁的锁模式和特点,以及行级锁和页面锁的特点和应用场景。同时还讨论了锁冲突对数据库并发访问性能的影响。 ... [详细]
  • Hibernate延迟加载深入分析-集合属性的延迟加载策略
    本文深入分析了Hibernate延迟加载的机制,特别是集合属性的延迟加载策略。通过延迟加载,可以降低系统的内存开销,提高Hibernate的运行性能。对于集合属性,推荐使用延迟加载策略,即在系统需要使用集合属性时才从数据库装载关联的数据,避免一次加载所有集合属性导致性能下降。 ... [详细]
  • LVS实现负载均衡的原理LVS负载均衡负载均衡集群是LoadBalance集群。是一种将网络上的访问流量分布于各个节点,以降低服务器压力,更好的向客户端 ... [详细]
author-avatar
一个幼儿女教师上
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有