概述 可以把 HTTPS 理解为 “穿着 SSL/TLS 盔甲的 HTTP”。

它的核心目标很简单:

在不安全的网络(如互联网)上建立一个安全的通信通道,确保数据传输的三大安全属性:

机密性:内容不会被窃听者解密完整性:内容在传输过程中未被篡改身份真实性:你连接的服务器就是你以为的那个服务器一、非对称加密与对称加密的结合HTTPS 的安全并非依赖单一技术,而是巧妙地结合了两种加密方式。

1. 对称加密Symmetric Encryption

代码语言:javascript复制// 示例:AES 对称加密(简化版)

const crypto = require('crypto');

const secretKey = 'my-super-secret-key-32'; // 同一把密钥用于加/解密

const message = "这是要加密的敏感信息";

// 加密

const encrypted = crypto.AES.encrypt(message, secretKey);

console.log("密文:", encrypted); // 输出乱码字符串

// 解密

const decrypted = crypto.AES.decrypt(encrypted, secretKey);

console.log("明文:", decrypted); // 恢复原文概念:加密和解密使用同一把密钥。优点:速度快,适合加密大量数据(如网页内容)。缺点:如何安全地把 secretKey 发送给对方?如果密钥在网络中明文传输,攻击者可截获并解密所有消息。2. 非对称加密Asymmetric Encryption

代码语言:javascript复制// 示例:RSA 非对称加密(Node.js crypto 模拟)

const { generateKeyPairSync } = require('crypto');

// 生成公钥/私钥对(仅演示用,生产环境需更强参数)

const { publicKey, privateKey } = generateKeyPairSync('rsa', {

modulusLength: 2048,

});

const data = "只有私钥能解开的信息";

// 客户端用公钥加密

const encryptedData = crypto.publicEncrypt(publicKey, Buffer.from(data));

console.log("公钥加密后:", encryptedData.toString('base64'));

// 服务器用私钥解密

const decryptedData = crypto.privateDecrypt(privateKey, encryptedData);

console.log("私钥解密后:", decryptedData.toString()); // 输出原文概念:一对密钥 —— 公钥 和 私钥 公钥加密 → 私钥解密(用于保密)私钥签名 → 公钥验证(用于认证)优点:解决了密钥分发问题。公钥可公开传播,即使被窃听也无法反向推导出私钥。缺点:运算慢,不适合频繁加密大块数据。3. HTTPS 的智慧:混合加密机制 用非对称加密交换密钥,用对称加密传输数据

代码语言:javascript复制// TLS 握手阶段:客户端生成预主密钥,并用服务器公钥加密发送

let preMasterSecret = generateRandomBytes(48); // 如 48 字节随机数

// 使用从证书中提取的服务器公钥进行加密

let encryptedPreMaster = RSA.encrypt(preMasterSecret, serverPublicKey);

// 发送给服务器

sendToServer('/tls-handshake', { encryptedPreMaster });

// 后续通信全部使用基于此生成的对称密钥

let sessionKey = deriveSessionKey(clientRandom, serverRandom, preMasterSecret);

useSymmetricEncryption(sessionKey); // 开始 AES 加密通信最终效果:

初始阶段通过非对称加密安全传递“会话密钥”后续通信采用高速对称加密(如 AES-GCM),兼顾安全性与性能二、数字证书(Digital Certificate)1. 问题引入如何确保你拿到的公钥是真实服务器的,而不是中间人伪造的?

危险场景:

代码语言:javascript复制客户端 ──→ 攻击者(伪装成服务器)──→ 真实服务器

↑ 截获并替换公钥 ↑攻击者用自己的公钥冒充服务器,即可完成“中间人攻击”。

2. 解决方案:数字证书数字证书就像服务器的“网络身份证”,由可信第三方——CA 颁发。

证书的数据结构示例(JSON 形式)代码语言:javascript复制{

"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)代码语言:javascript复制// 伪代码:浏览器验证证书流程

function validateCertificate(cert, rootCAs) {

// 1. 检查有效期

if (new Date() < cert.validFrom || new Date() > cert.validTo) {

throw new Error("证书已过期");

}

// 2. 检查域名匹配

if (!cert.extensions.altNames.includes(currentDomain)) {

throw new Error("域名不匹配");

}

// 3. 验证签名:使用签发者(Issuer)的公钥验证签名

const issuerPublicKey = getTrustedCAPublicKey(cert.issuer);

const dataToVerify = serializeWithoutSignature(cert);

if (!RSA.verifySignature(dataToVerify, cert.caSignature, issuerPublicKey)) {

throw new Error("证书签名无效,可能被篡改");

}

console.log(" 证书验证通过!");

return true;

} 若任一检查失败 → 浏览器弹出警告:“您的连接不是私密连接”

三、HTTPS 通信全过程(TLS 握手详解)这是 HTTPS 安全通信的核心环节。以下每一步都配有模拟代码或数据交互示意。

步骤 1:Client Hello客户端发起连接请求:

代码语言:javascript复制GET / HTTP/1.1

Host: www.example.com

Connection: Upgrade

Upgrade: tls/1.3同时发送 TLS 层信息(不在 HTTP 头中):

代码语言:javascript复制{

"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"]

}

} 这些信息告诉服务器:“我能支持哪些加密方式,请你选一个。”

步骤 2:Server Hello服务器选择最优配置并回应:

代码语言:javascript复制{

"selectedTlsVersion": "TLSv1.3",

"selectedCipherSuite": "TLS_AES_128_GCM_SHA256",

"serverRandom": "f6e5d4c3b2a1...", // 服务器生成的随机数

"certificate": {

"subject": "www.example.com",

"publicKey": "-----BEGIN PUBLIC KEY-----...",

"caSignature": "3045022100b9d..."

}

} 至此,客户端已获得服务器证书和两个随机数。

步骤 3:证书验证客户端执行自动验证(无需用户干预,除非出错):

代码语言:javascript复制try {

verifyCertificate(serverCert);

} catch (error) {

showBrowserWarning(` 安全警告:${error.message}`);

blockPageLoad();

}常见错误提示:

“此网站的安全证书有问题”“NET::ERR_CERT_DATE_INVALID”“无法验证此证书是由受信任的机构颁发的”步骤 4:生成预主密钥(Pre-Master Secret)代码语言:javascript复制// 客户端行为

const preMasterSecret = generateRandomBytes(48); // 如 ECDHE 中的共享密钥

// 从证书中提取公钥

const serverPublicKey = parsePublicKeyFromCert(serverCert);

// 用公钥加密预主密钥(TLS 1.2 及以前)

const encryptedPreMaster = RSA.encrypt(preMasterSecret, serverPublicKey);

// 发送给服务器

sendEncryptedPreMaster(encryptedPreMaster); 注意:现代 TLS(如 1.3)通常使用 ECDHE 密钥交换,不再需要加密预主密钥,而是通过椭圆曲线计算达成共识,具备前向安全性。

步骤 5:服务器解密预主密钥代码语言:javascript复制// 服务器行为(TLS 1.2)

const encryptedPreMaster = receiveFromClient();

// 使用自己的私钥解密

const preMasterSecret = RSA.decrypt(encryptedPreMaster, privateKey);

if (!preMasterSecret) {

terminateConnection("预主密钥解密失败");

} 私钥始终保存在服务器本地,绝不外泄!

步骤 6:生成会话密钥(Session Key)双方使用三个随机数生成相同的会话密钥:

代码语言:javascript复制// 伪函数:PRF 是伪随机函数(Pseudo-Random Function)

function generateMasterSecret(preMasterSecret, clientRandom, serverRandom) {

return PRF(preMasterSecret, 'master secret', clientRandom + serverRandom, 48);

}

function deriveSessionKey(masterSecret, label = 'key expansion') {

return PRF(masterSecret, label, serverRandom + clientRandom, 32); // 例如 AES-256 密钥

}

// 双方独立计算,结果一致

const masterSecret = generateMasterSecret(preMasterSecret, clientRandom, serverRandom);

const sessionKey = deriveSessionKey(masterSecret);

console.log("🎯 会话密钥生成完成:", sessionKey.toString('hex')); 只要输入相同,输出就相同 —— 这是数学的魅力!

步骤 7:握手完成,开始安全通信代码语言:javascript复制// 客户端发送加密的 Finished 消息

const finishedMessage = "handshake_finished";

const encryptedFinished = AES.encrypt(finishedMessage, sessionKey, iv);

send(encryptedFinished);

// 服务器解密并验证

const received = AES.decrypt(encryptedFinished, sessionKey, iv);

if (received === "handshake_finished") {

sendAck(); // 回应确认

startSecureHTTP(); // 正式进入 HTTPS 通信

}从此以后:

所有 HTTP 请求和响应都被封装在 TLS 记录层中,经过对称加密传输:

代码语言:javascript复制[TLS RECORD LAYER]

Content-Type: ApplicationData

Encrypted Payload: a1b2c3d4e5f6...四、HTTPS 如同寄密信(带代码类比)想象你要通过一个不安全的邮递系统(互联网)给朋友(服务器)寄一封密信。

1. 获取公钥(证书)朋友先通过权威公证处(CA)公证了他的公开信箱(公钥),并把公证书寄给你。

代码语言:javascript复制// 你收到证书后验证它是否可信

const cert = downloadCertificate("https://friend.com");

validateCertificate(cert, trustedCAList); // 返回 true 表示可信2. 传递密钥(握手)你写一封信,里面装着一把保险箱的钥匙(会话密钥),然后放进朋友的公开信箱(用公钥加密),寄出去。

代码语言:javascript复制const sessionKey = generateSessionKey();

const encryptedKey = RSA.encrypt(sessionKey, friendPublicKey);

mail.send("公开信箱", encryptedKey); 即使信被截获,别人没有朋友的私人钥匙(私钥),也打不开信箱。

3. 朋友拿到钥匙朋友用他的私人钥匙打开信箱,取出保险箱钥匙。

代码语言:javascript复制const encryptedKey = mail.receive();

const sessionKey = RSA.decrypt(encryptedKey, friendPrivateKey);

console.log("🔑 会话密钥已就位!");4. 安全通信开始现在你们都有了同一把保险箱钥匙。之后所有的信件都放进这个保险箱邮寄,既安全又快捷。

代码语言:javascript复制// 日常通信

function sendSecureMessage(msg, key) {

const encrypted = AES.encrypt(msg, key);

return transmitOverInternet(encrypted);

}

function readSecureMessage(encryptedMsg, key) {

const plainText = AES.decrypt(encryptedMsg, key);

return plainText;

}五、关键要点回顾(附代码说明)要点

说明

关键代码体现

混合加密

非对称加密用于交换密钥,对称加密用于传输数据

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++ 和底层协议栈,此处为高度简化模型。