
HTTP 和 HTTPS 就差一个 S凭啥一个被浏览器骂不安全不知道朋友们有没有过这种经历自己辛辛苦苦本地起了个服务浏览器地址栏敲http://localhost:8080是岁月静好可一旦部署到服务器上用域名http://一访问浏览器立马给你甩脸子——要么是个大大的不安全要么直接警告你与此网站之间建立的连接并非私密连接。咱当时就懵了HTTP 和 HTTPS 不就差一个字母 S 吗咋差距跟我跟马云都姓马一样离谱捏更离谱的是去面试的时候面试官一句说说 HTTPS 的加密过程能把一堆人问得哑口无言。咱明明每天都在用 HTTPS却说不清楚它到底把 HTTP 怎么了 (꒦ິ⌓꒦ີ)所以这篇就来把这个事掰开揉碎了讲清楚——它不背八股咱就聊明白 HTTP 有啥毛病、HTTPS 是怎么一个一个把毛病治好的。看完之后面试再被问到你也能跟面试官唠上两句。一、HTTP 到底是个啥先用大白话说HTTP超文本传输协议就是浏览器和服务器之间聊天用的一套规矩。你打开一个网页本质上是这么个流程浏览器客户端跟服务器说“我要/index.html这个文件”服务器把文件内容回给你浏览器拿到 HTML再按里面的内容去要 CSS、JS、图片……就这么一来一回靠的就是 HTTP。它规定了请求长什么样、“响应长什么样”、用哪个方法GET/POST 啥的这些格式问题。那你有没有想过一个问题浏览器和服务器之间的这些聊天记录是怎么传到对方那儿的答案是通过一大堆网络设备你的路由器 → 运营商 → 各种骨干网节点 → 目标服务器所在的机房……中间要经过多少个节点谁也说不准。关键来了HTTP 传输的东西是明文的。啥叫明文就是原原本本、不加任何遮挡地传。这就好比你去寄快递但是没装箱、没封口里面的东西一路裸奔到收件人手里中途任何一个经手的人都能直接看到、甚至顺手改一改。平时传个今天天气不错那当然无所谓可你要是传的是账号密码、身份证号、银行卡号、支付验证码呢想想就后背发凉 (•́︿•̀)二、HTTP 的三大原罪咱把 HTTP 的问题总结成三条江湖人称三大原罪罪一窃听别人能看见因为明文传输数据经过的任何一台中间设备比如公共 WiFi 的路由器都能把你的聊天内容看个精光。你在星巴克连个免费 WiFi随手填个登录密码旁边坐着的大哥可能就把你密码抄走了。罪二篡改别人能改更狠的是中间人不仅能看到还能改了再转给对方。比如你请求一个网页中间人偷偷在返回的 HTML 里塞了一段广告代码、或者把页面里的转账给张三改成转账给李四你这边完全不知情。罪三冒充别人能装还有一招叫冒充中间人直接假装自己就是目标服务器跟你建立连接。你以为你在跟银行聊其实全程是在跟骗子聊。;// 直接用 https剩下的交给 JDKHttpRequestrequestHttpRequest.newBuilder().uri(URI.create(https://api.github.com/users/octocat)).GET().build();HttpResponseStringresponseclient.send(request,HttpResponse.BodyHandlers.ofString());System.out.println(response.body());Spring 的RestTemplate、WebClient也是同理写https://就完事了因为 JDK 内置了一个叫做cacerts的信任库里面躺着全球各大 CA 的根证书验签全靠它。那啥时候会翻车捏当你访问的是自签名证书自己给自己签的证书的网站时。比如公司内网的一些服务、测试环境、咱自己用keytool签的证书这类证书没有 CA 背书浏览器和 Java 都会认为这证书来路不明直接拒绝连接。浏览器里你还能点个继续前往不安全强行闯过去但在 Java 代码里它会直接给你甩一个异常javax.net.ssl.SSLHandshakeException:PKIXpath building failed:sun.security.provider.certpath.SunCertPathBuilderException:unabletofindvalid certification pathtorequestedtarget这一长串看着吓人翻译过来其实是“这证书我没见过也没人给它背书我不敢跟它聊。”两个解决办法方案一把证书导入 JDK 的信任库推荐正规做法把这些自签名证书导入到 JDK 的cacerts信任库里之后 JDK 就认它了。用 JDK 自带的keytool工具# 1. 先从网站上把证书导出来浏览器点锁图标就能导出# 假设导出来叫 server.crt# 2. 导入到 JDK 的信任库keytool-import-trustcacerts-aliasmyserver\-fileserver.crt\-keystore$JAVA_HOME/lib/security/cacerts\-storepasschangeit注意cacerts默认密码就是changeit这是个大家都知道的公开密码生产环境记得改。另外你这么导是改的本机 JDK换个环境部署又得重新导一遍有点烦但最正规。方案二代码里信任所有证书方便但只能测试用有些朋友觉得导证书太麻烦就想在代码里一把梭——搞一个什么都信的TrustManager// ⚠️ 警告这么写会完全放弃证书校验等于裸奔生产环境千万别用TrustManager[]trustAllnewTrustManager[]{newX509TrustManager(){publicvoidcheckClientTrusted(X509Certificate[]c,Stringa){}// 不检查publicvoidcheckServerTrusted(X509Certificate[]c,Stringa){}// 不检查publicX509Certificate[]getAcceptedIssuers(){returnnewX509Certificate[0];}}};这么写 HTTPS 就白上了——中间人攻击、冒充全都防不住了纯粹是把 HTTPS 当成 HTTP 在用。所以这个法子只能在本地测试图个方便千万别带进生产代码。咱踩过这个坑当年图省事上线了后来被安全扫描揪出来一通批评 (ŏ_ŏ)八、几个咱踩过的坑除了证书实际开发里还有几个常见坑提前给你们排一排。坑一HTTP 页面里混着 HTTPS 资源 → 浏览器拦截浏览器现在有个规矩HTTPS 页面里不允许再加载 HTTP 的图片/脚本/接口这叫混合内容Mixed Content会被直接拦掉。表现就是页面明明开了 HTTPS但图片不显示、接口报错。排查思路打开浏览器 F12看看 Console 里是不是一堆Mixed Content的报错把那些 http:// 的资源全换成 https:// 就行。坑二证书过期前面说过证书有有效期一般 1 年Let’s Encrypt 的免费证书是 90 天。忘了续期网站直接访问不了用户看到的是一片红色的警告页。建议用 Let’s Encrypt 的话把自动续期配上certbot renew或者干脆用云厂商的免费证书 监控到期时间。这个坑坑过无数团队包括一些大厂。坑三老 JDK 不支持的 TLS 版本有些老项目还跑在 JDK 8 早期版本上遇到只支持 TLS 1.3 的服务器握手会失败。排查思路用curl -v https://your-server.com看看握手协商的 TLS 版本再对照 JDK 支持的版本。升级 JDK 或手动开启高版本 TLS 通常能解决。坑四HTTPS 就一定安全吗不是。HTTPS 保证的是传输过程的安全不保证网站本身是好人。一个钓鱼网站照样可以申请合法证书、挂上 HTTPS。所以看到那个小锁只能说明你和这个网站之间的传输是加密的不能说明这个网站可信。这个区别咱心里要有数。九、总结一下咱用一张表把 HTTP 和 HTTPS 的差别收个尾对比项HTTPHTTPS全称超文本传输协议HTTP TLS传输方式明文加密默认端口80443能否防窃听/篡改/冒充都不能都能需要证书吗不需要需要CA 签发速度略快少一次握手略慢多一层加解密但影响很小一句话概括这篇的核心HTTP 只管把话传到不管路上的安全HTTPS 在 HTTP 下面垫了一层 TLS通过非对称加密换对称密钥 数字证书验明正身把窃听、篡改、冒充这三大原罪挨个治好了。现在你再看浏览器地址栏那个小锁是不是感觉完全不一样了嘿嘿。给个实践建议现在做项目https://基本已经是默认选项了。Let’s Encrypt 的证书免费、能自动续期配合 Nginx 配一下也就十几分钟的事不折腾的话云厂商控制台点几下也能一键申请。没有任何理由让自己的网站还裸奔在 HTTP 上。以上是个人的一些经验分享原理部分已经尽量说人话嘞。如果有哪里有什么错误的地方也请大佬们不吝指出咱一起学习进步本文完结撒花ヾ(≧▽≦*)o