一个很常见的现象
你给网站装了 SSL 证书,浏览器地址栏出现了小锁。但打开开发者工具,控制台里躺着一行红字:
Mixed Content: The page at 'https://example.com/' was loaded over HTTPS,
but requested an insecure element 'http://example.com/img.png'.
页面看起来还是正常的,图片却裂了,或者某个接口一直失败。
另一头的常见对话是:别人问 HTTPS 比 HTTP 安全在哪,你能答“加密”;再往下问加密了什么、谁来加密、怎么确认对面不是假冒的,就说不清了。
这两个问题其实是同一个知识点的两端。下面从一次真实访问拆开讲。
HTTP 明文带来三个具体麻烦
HTTP 的设计年代(1991 年)没有把“链路中间有攻击者”当成前提。明文传输导致三件事:
- 能被看见。同一个 WiFi 下别人抓包,就能看到你提交的表单内容、Cookie 原文。密码如果在没有 HTTPS 的页面上提交,等于明文广播出去。
- 能被修改。中间人可以往响应里插入任意内容。2015 年前后国内运营商在 HTTP 页面里插广告就是这么干的——你访问一个网页,页面上多出一个不是站长放的悬浮广告。这不是网站被黑,是链路被改了。
- 对面可能不是你以为的服务器。DNS 被污染、或者被 ARP 欺骗导到另一台机器上,你看到的是一个一模一样的假登录页。HTTP 层面没有任何机制能发现这件事。
HTTPS 针对的正是这三点:加密解决“被看见”,完整性校验解决“被修改”,证书解决“对面是谁”。
HTTPS 不是新协议,是在 TCP 上又加了一层
层次关系是:HTTP → TLS → TCP → IP。HTTP 报文本身一个字没变,只是被 TLS 装进加密信封再交给 TCP。
所以 HTTPS 的默认端口是 443 而不是 80;它也不是“另一个协议”,只是 URL scheme 写 https 时,客户端知道要先握手。
握手到底在做什么
握手要解决两件事:确认对面身份,商量出一个只有双方知道的密钥。分开看。
第一件:证书链验证
服务器出示的不是一张证书,而是一条链:
- 服务器证书:写着域名、公钥、有效期,由中间 CA 签名。
- 中间证书:由根 CA 签名。
- 根证书:预装在操作系统和浏览器里,不需要服务器发送。
浏览器从服务器证书一路往上验签名,直到撞上一个自己信得过的根。任何一环缺失或不匹配都会报错。
最常见的配置错误:只装了服务器证书,忘了装中间证书。结果是 Chrome 和 Firefox 因为能自己补链而一切正常,但老版本 Android、Java 客户端、部分 App 内置浏览器直接报证书错误。这类故障只在不常用的设备上暴露,非常难查。
用一条命令看自己的站点发了几张证书:
echo | openssl s_client -showcerts -connect mcstudio.top:443
-servername mcstudio.top 2>/dev/null | grep -c "BEGIN CERTIFICATE"
输出 1 说明只发了服务器证书;正常应该是 2,即服务器证书加中间证书。
第二件:密钥协商
现代 TLS 用 ECDHE 协商会话密钥。它的特点是前向安全:会话密钥只在内存里存在过,不落地保存。即使以后服务器的私钥泄漏,攻击者也无法解密他以前录下的流量。
TLS 1.2 完整握手需要 2 个 RTT 才能开始传数据;TLS 1.3 压缩到 1 个 RTT,会话恢复时甚至 0-RTT。这就是为什么同一条线路升级到 TLS 1.3 后,首字节时间会明显变短。
怎么确认自己的站真的配好了
三件事:强制跳转、没有混合内容、证书有效且自动续期。
- 访问
http://你的域名,应返回 301 跳到 https 版本。 - F12 控制台刷新首页和任意文章页,不应出现 Mixed Content 警告。
- 确认证书到期时间,以及自动续期真的在跑。
第三条值得单独说。Let’s Encrypt 的证书只有 90 天有效期,靠定时任务续期,而续期失败往往是静默的。到期那天网站直接从“正常”变成“全站红色警告”,你可能一周都没打开过自己的站。
echo | openssl s_client -connect mcstudio.top:443
-servername mcstudio.top 2>/dev/null | openssl x509 -noout -dates -issuer
输出会给出 notBefore(生效时间)、notAfter(到期时间)和签发者。正确做法是加一个监控:剩余天数少于 20 天就提醒,别等出事。
混合内容:最容易被忽略的一类“HTTPS 没配好”
页面本身是 https,但里面引用了 http:// 的图片、JS、CSS 或 iframe。浏览器会降级提示甚至直接拦截,因为“整个页面是安全的”这个承诺被一个明文资源打破了。
排查很直接,抓一次首页看还有多少 http 引用:
curl -s https://mcstudio.top/ | grep -o 'http://[^"]*' | sort -u | head -20
常见的三类来源:文章里手写的图片地址、主题里写死的 CDN 地址、以及数据库里从 http 时代遗留下来的绝对路径。最后一种必须改数据库(把 http://你的域名 批量替换成 https://你的域名),改之前先备份,并且先在一个临时站点上试一遍。
HTTPS 不能解决什么
说清边界和说清作用一样重要:
- 它不隐藏你访问了哪个域名。SNI 默认是明文的(ECH 还没普及)。
- 它不隐藏流量大小和时间,也防不住“这个 IP 在跟那个 IP 通信”这类元数据。
- 它不保证网站内容可信。钓鱼站也能申请免费证书,小锁只说明链路加密,不说明这是好人。
- 它不替代服务器本身的安全。证书再正确,后台用
admin / 123456一样被登进去。
小结
把 HTTPS 理解成“HTTP 报文 + 一次身份核验 + 一次密钥协商 + 全程加密和完整性校验”,配置失败的绝大多数情况就归到三处:证书链不全、页面里有明文资源、续期没生效。这三处都能用上面几条命令在几分钟内查清楚。
遇到访问异常时先分清是链路问题还是应用问题,可以对照 HTTP 状态码大全 看服务端返回的到底是哪一类错误——502 和 404 指向的原因完全不同。
相关:HTTPS 证书链与中间证书——知道两者差别之后,下一步是让那张证书真的被所有人信任。










暂无评论内容