深入浅出解析 HTTPS 原理 目录概述一、非对称加密与对称加密的结合1. 对称加密2. 非对称加密3. HTTPS 的智慧混合加密机制二、数字证书Digital Certificate1. 问题引入2. 解决方案数字证书证书的数据结构示例JSON 形式3.信任链机制Certificate Chain三、HTTPS 通信全过程TLS 握手详解步骤 1Client Hello步骤 2Server Hello步骤 3证书验证步骤 4生成预主密钥Pre-Master Secret步骤 5服务器解密预主密钥步骤 6生成会话密钥Session Key步骤 7握手完成开始安全通信四、HTTPS 如同寄密信带代码类比1. 获取公钥证书2. 传递密钥握手3. 朋友拿到钥匙4. 安全通信开始五、关键要点回顾附代码说明六、总结概述可以把 HTTPS 理解为“穿着 SSL/TLS 盔甲的 HTTP”。它的核心目标很简单在不安全的网络如互联网上建立一个安全的通信通道确保数据传输的三大安全属性机密性内容不会被窃听者解密完整性内容在传输过程中未被篡改身份真实性你连接的服务器就是你以为的那个服务器一、非对称加密与对称加密的结合HTTPS 的安全并非依赖单一技术而是巧妙地结合了两种加密方式。1. 对称加密Symmetric Encryption// 示例AES 对称加密简化版constcryptorequire(crypto);constsecretKeymy-super-secret-key-32;// 同一把密钥用于加/解密constmessage这是要加密的敏感信息;// 加密constencryptedcrypto.AES.encrypt(message,secretKey);console.log(密文:,encrypted);// 输出乱码字符串// 解密constdecryptedcrypto.AES.decrypt(encrypted,secretKey);console.log(明文:,decrypted);// 恢复原文概念加密和解密使用同一把密钥。优点速度快适合加密大量数据如网页内容。缺点如何安全地把secretKey发送给对方如果密钥在网络中明文传输攻击者可截获并解密所有消息。2. 非对称加密Asymmetric Encryption// 示例RSA 非对称加密Node.js crypto 模拟const{generateKeyPairSync}require(crypto);// 生成公钥/私钥对仅演示用生产环境需更强参数const{publicKey,privateKey}generateKeyPairSync(rsa,{modulusLength:2048,});constdata只有私钥能解开的信息;// 客户端用公钥加密constencryptedDatacrypto.publicEncrypt(publicKey,Buffer.from(data));console.log(公钥加密后:,encryptedData.toString(base64));// 服务器用私钥解密constdecryptedDatacrypto.privateDecrypt(privateKey,encryptedData);console.log(私钥解密后:,decryptedData.toString());// 输出原文概念一对密钥 ——公钥和私钥公钥加密 → 私钥解密用于保密私钥签名 → 公钥验证用于认证优点解决了密钥分发问题。公钥可公开传播即使被窃听也无法反向推导出私钥。缺点运算慢不适合频繁加密大块数据。3. HTTPS 的智慧混合加密机制用非对称加密交换密钥用对称加密传输数据// TLS 握手阶段客户端生成预主密钥并用服务器公钥加密发送letpreMasterSecretgenerateRandomBytes(48);// 如 48 字节随机数// 使用从证书中提取的服务器公钥进行加密letencryptedPreMasterRSA.encrypt(preMasterSecret,serverPublicKey);// 发送给服务器sendToServer(/tls-handshake,{encryptedPreMaster});// 后续通信全部使用基于此生成的对称密钥letsessionKeyderiveSessionKey(clientRandom,serverRandom,preMasterSecret);useSymmetricEncryption(sessionKey);// 开始 AES 加密通信最终效果初始阶段通过非对称加密安全传递“会话密钥”后续通信采用高速对称加密如 AES-GCM兼顾安全性与性能二、数字证书Digital Certificate1. 问题引入如何确保你拿到的公钥是真实服务器的而不是中间人伪造的危险场景客户端 ──→ 攻击者伪装成服务器──→ 真实服务器 ↑ 截获并替换公钥 ↑攻击者用自己的公钥冒充服务器即可完成“中间人攻击”。2. 解决方案数字证书数字证书就像服务器的“网络身份证”由可信第三方——CA 颁发。证书的数据结构示例JSON 形式{subject:{commonName:www.example.com,organization:Example Inc.,country:US},issuer:{commonName:DigiCert TLS RSA SHA256 2020 CA1,organization:DigiCert Inc,country:US},publicKey:-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...\n-----END PUBLIC KEY-----,validFrom:2025-01-01T00:00:00Z,validTo:2026-01-01T23:59:59Z,signatureAlgorithm:sha256WithRSAEncryption,fingerprint:A1:B2:C3:D4:E5:F6:78:90...,extensions:[{name:subjectAltName,altNames:[example.com,*.example.com]}],caSignature:3045022100b9d...fcda// CA 对整个证书内容的数字签名}浏览器收到该证书后会使用内置的 CA 根证书公钥来验证caSignature是否有效。3.信任链机制Certificate Chain// 伪代码浏览器验证证书流程functionvalidateCertificate(cert,rootCAs){// 1. 检查有效期if(newDate()cert.validFrom||newDate()cert.validTo){thrownewError(证书已过期);}// 2. 检查域名匹配if(!cert.extensions.altNames.includes(currentDomain)){thrownewError(域名不匹配);}// 3. 验证签名使用签发者Issuer的公钥验证签名constissuerPublicKeygetTrustedCAPublicKey(cert.issuer);constdataToVerifyserializeWithoutSignature(cert);if(!RSA.verifySignature(dataToVerify,cert.caSignature,issuerPublicKey)){thrownewError(证书签名无效可能被篡改);}console.log( 证书验证通过);returntrue;}若任一检查失败 → 浏览器弹出警告“您的连接不是私密连接”三、HTTPS 通信全过程TLS 握手详解这是 HTTPS 安全通信的核心环节。以下每一步都配有模拟代码或数据交互示意。步骤 1Client Hello客户端发起连接请求GET / HTTP/1.1 Host: www.example.com Connection: Upgrade Upgrade: tls/1.3同时发送 TLS 层信息不在 HTTP 头中{tlsVersion:[TLSv1.2,TLSv1.3],cipherSuites:[TLS_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA],clientRandom:a1b2c3d4e5f6...,// 32 字节随机数extensions:{supported_groups:[secp256r1,x25519],signature_algorithms:[rsa_pkcs1_sha256]}}这些信息告诉服务器“我能支持哪些加密方式请你选一个。”步骤 2Server Hello服务器选择最优配置并回应{selectedTlsVersion:TLSv1.3,selectedCipherSuite:TLS_AES_128_GCM_SHA256,serverRandom:f6e5d4c3b2a1...,// 服务器生成的随机数certificate:{subject:www.example.com,publicKey:-----BEGIN PUBLIC KEY-----...,caSignature:3045022100b9d...}}至此客户端已获得服务器证书和两个随机数。步骤 3证书验证客户端执行自动验证无需用户干预除非出错try{verifyCertificate(serverCert);}catch(error){showBrowserWarning(安全警告${error.message});blockPageLoad();}常见错误提示“此网站的安全证书有问题”“NET::ERR_CERT_DATE_INVALID”“无法验证此证书是由受信任的机构颁发的”步骤 4生成预主密钥Pre-Master Secret// 客户端行为constpreMasterSecretgenerateRandomBytes(48);// 如 ECDHE 中的共享密钥// 从证书中提取公钥constserverPublicKeyparsePublicKeyFromCert(serverCert);// 用公钥加密预主密钥TLS 1.2 及以前constencryptedPreMasterRSA.encrypt(preMasterSecret,serverPublicKey);// 发送给服务器sendEncryptedPreMaster(encryptedPreMaster);注意现代 TLS如 1.3通常使用ECDHE 密钥交换不再需要加密预主密钥而是通过椭圆曲线计算达成共识具备前向安全性。步骤 5服务器解密预主密钥// 服务器行为TLS 1.2constencryptedPreMasterreceiveFromClient();// 使用自己的私钥解密constpreMasterSecretRSA.decrypt(encryptedPreMaster,privateKey);if(!preMasterSecret){terminateConnection(预主密钥解密失败);}私钥始终保存在服务器本地绝不外泄步骤 6生成会话密钥Session Key双方使用三个随机数生成相同的会话密钥// 伪函数PRF 是伪随机函数Pseudo-Random FunctionfunctiongenerateMasterSecret(preMasterSecret,clientRandom,serverRandom){returnPRF(preMasterSecret,master secret,clientRandomserverRandom,48);}functionderiveSessionKey(masterSecret,labelkey expansion){returnPRF(masterSecret,label,serverRandomclientRandom,32);// 例如 AES-256 密钥}// 双方独立计算结果一致constmasterSecretgenerateMasterSecret(preMasterSecret,clientRandom,serverRandom);constsessionKeyderiveSessionKey(masterSecret);console.log( 会话密钥生成完成:,sessionKey.toString(hex));只要输入相同输出就相同 —— 这是数学的魅力步骤 7握手完成开始安全通信// 客户端发送加密的 Finished 消息constfinishedMessagehandshake_finished;constencryptedFinishedAES.encrypt(finishedMessage,sessionKey,iv);send(encryptedFinished);// 服务器解密并验证constreceivedAES.decrypt(encryptedFinished,sessionKey,iv);if(receivedhandshake_finished){sendAck();// 回应确认startSecureHTTP();// 正式进入 HTTPS 通信}从此以后所有 HTTP 请求和响应都被封装在 TLS 记录层中经过对称加密传输[TLS RECORD LAYER] Content-Type: ApplicationData Encrypted Payload: a1b2c3d4e5f6...四、HTTPS 如同寄密信带代码类比想象你要通过一个不安全的邮递系统互联网给朋友服务器寄一封密信。1. 获取公钥证书朋友先通过权威公证处CA公证了他的公开信箱公钥并把公证书寄给你。// 你收到证书后验证它是否可信constcertdownloadCertificate(https://friend.com);validateCertificate(cert,trustedCAList);// 返回 true 表示可信2. 传递密钥握手你写一封信里面装着一把保险箱的钥匙会话密钥然后放进朋友的公开信箱用公钥加密寄出去。constsessionKeygenerateSessionKey();constencryptedKeyRSA.encrypt(sessionKey,friendPublicKey);mail.send(公开信箱,encryptedKey);即使信被截获别人没有朋友的私人钥匙私钥也打不开信箱。3. 朋友拿到钥匙朋友用他的私人钥匙打开信箱取出保险箱钥匙。constencryptedKeymail.receive();constsessionKeyRSA.decrypt(encryptedKey,friendPrivateKey);console.log( 会话密钥已就位);4. 安全通信开始现在你们都有了同一把保险箱钥匙。之后所有的信件都放进这个保险箱邮寄既安全又快捷。// 日常通信functionsendSecureMessage(msg,key){constencryptedAES.encrypt(msg,key);returntransmitOverInternet(encrypted);}functionreadSecureMessage(encryptedMsg,key){constplainTextAES.decrypt(encryptedMsg,key);returnplainText;}五、关键要点回顾附代码说明要点说明关键代码体现混合加密非对称加密用于交换密钥对称加密用于传输数据RSA.encrypt(preMaster)AES.encrypt(payload)数字证书包含公钥 CA 签名防止伪造verifySignature(cert.data, cert.signature, caPubKey)TLS 握手建立安全连接的关键过程ClientHello → ServerHello → Certificate → PreMaster → SessionKey三重随机数客户端随机 服务器随机 预主密钥 → 唯一会话密钥PRF(preMaster, randomA randomB)前向安全性即使未来私钥泄露也无法解密过去的通信使用 ECDHE 密钥交换每次会话密钥独立现代 TLS 1.3 已默认启用前向安全性废弃静态 RSA 密钥交换。六、总结HTTPS 并不是一种全新的协议而是HTTP TLS/SSL的安全组合。它通过数字证书验证身份 我连的是真的银行网站非对称加密建立信任 安全传递密钥对称加密保障性能 快速加密网页内容在开放网络中构建出一条“加密隧道”让我们可以安全地浏览网页、登录账号、进行支付。下次当你看到浏览器地址栏的小锁图标时就知道背后正有一场精密而优雅的加密握手在悄然完成。本文参考 TLS 1.2/1.3 协议设计原理结合 Node.js crypto API 风格编写示例代码旨在帮助初学者理解 HTTPS 底层机制。实际实现涉及 C/C 和底层协议栈此处为高度简化模型。