跳到主要内容
JackSparrow414
返回

理解HTTPS/TLS/SSL(一)基础概念+配置本地自签名证书

本文导航

展开本文导航

正文

对于HTTPS、TLS、SSL相关的概念,平时也是时常接触到。看过几篇文章之后,总以为自己真正了解了,实际上并没有,准备补充一下这一部分的基础知识,对于更深层次的东西,例如各种标准的解读,则不打算深入。

没有HTTPS时的样子

我们都知道HTTP是不安全的,以及为什么不安全。但是为了更直观的说明以及加深理解,做一个简单的模拟,我使用WireShark作为辅助工具。

场景模拟

本地建一个简单Restful Java项目,并部署到Tomcat中。

WireShark的Capture Filter和Display Filter

设置Capture Filter

我们只去抓本地的包,所以在开始抓包之前,在用户界面中选择Loopback, 并设置Capture Filter

src host localhost and dst host localhost

Wireshark 欢迎页中为回环接口设置捕获过滤器 回车,开始进行抓包。

Capture Filter的相关语法可以在 WireShark软件用户界面 > Help > Wiki > CaptureFilters 中找到 > Further Information(pcap-filter man page ) 全部语法

启动程序

本地启动测试程序, IDEA中Tomcat的配置中应该只配HTTP Port,我这里配置的是8080.

在终端进行post请求

curl -X POST http://localhost:8080/validation/valid/inline/post

设置Display Filter过滤抓到的包

设置Display Filter

http and tcp.port eq 8080

Wireshark 抓取 HTTP 流量并显示请求明文 Display Filter的相关语法可以

结论

上面的场景模拟概括成一句话就是: HTTP是裸奔的。任何数据在网络中传播都是以明文的形式,使用抓包工具即可截获报文,甚至可能对其进行修改。这种危害可太恐怖了,所有使用网络与各种服务交互的人,各种隐私轻轻松松就泄露出去了。

关于为什么加密更简洁有力的回答

为了解决裸奔的问题,势必要对通信进行加密并解决中间人攻击问题。

关于为什么需要加密,更详细的说明可参考cloudflare官方的一篇博客,比我的语言更准确。以下内容引自上述博客的中文版

  1. 隐私:加密可确保除预期的收件人或正当的数据所有者以外,任何人都无法读取静止的通信或数据。这可以防止攻击者、广告网络、互联网服务提供商以及(在某些情况下)政府拦截和读取敏感数据,保护用户隐私。

  2. 安全性:无论是传输中的数据还是静止数据,加密都有助于防止数据泄露。如果公司设备丢失或被盗,且其硬盘驱动器已适当加密,则该设备上的数据将仍是安全的。类似地,加密通信使通信双方能够交换敏感数据而不会泄露数据。

  3. 数据完整性: 加密还有助于防止恶意行为,如在途攻击。当数据在互联网上传输时,加密可确保收件人收到的内容在途中没有被查看或篡改过。

  4. 法规:出于所有这些原因,许多行业和政府法规要求处理用户数据的公司对这些数据进行加密。需要加密的法规与合规性标准的示例包括 HIPAA、PCI-DSS 和 GDPR。

对称加密和非对称加密和CA证书

密钥交换

那么如何解决中间人攻击呢?下文CA证书部分会详细解释。

对称加密

对称加密的只有一把key,这个key既可以用来加密信息,也可以用来解密信息。

这就是它的缺点,只要能拿到密钥,则可以解密、加密信息。

非对称加密

CA机构和证书

不管是对称加密还是非对称加密,都有一个问题是如何解决中间人攻击?

于是引入信任的第三方机构来解决, 来自keystore文档中的解释

In a large-scale networked environment, it is impossible to guarantee that prior relationships between communicating entities were established or that a trusted repository exists with all used public keys. Certificates were invented as a solution to this public key distribution problem. Now a Certification Authority (CA) can act as a trusted third party

可以看到,CA机构主要的作用就是告诉客户端连接的是真正的想要通信的服务端,而不是中间人所伪造出来的。

但是问题又来了,中间人攻击既然可以冒充服务器,为什么不能冒充CA机构呢?

如何解决客户端和CA机构之间的信任问题?

当CA机构把证书返回给客户端时,客户端要使用CA机构的公钥去验证该证书的数字签名是不是真的CA机构签发的。那CA机构的公钥也很多吗?

这带来几个疑问

  1. 等等…这不又是服务端(CA机构)、客户端的问题了?为了防止套娃,CA机构包含公钥的证书都是默认安装在操作系统里的,CA机构毕竟不是很多,可以直接预置
  2. 关于此问题更详细的解释可参考man-in-the-middle-attack-possible-even-with-ca-certificate-and-assymetric-encry这个回答,这个回答里解释了为什么CA不太可能出现中间人攻击
  3. 这里也同时说明了在这一阶段为什么要用非对称加密,假设用的对称加密,那CA机构的密钥一旦被破解,那么都可以冒充CA机构,后果不可想象。

使用Java的keytool生成公钥和私钥和自签名证书

快捷命令

keytool -h

下列命令会生成密钥对和自签名证书

keytool -genkey -alias tomcat -keyalg RSA

genkey和genkeypair是一样的

The command uses the default SHA256withRSA signature algorithm to create a self-signed certificate that includes the public key and the distinguished name information. The certificate is valid for 180 days

默认生成的文件名是.keystore,引用自Keytool文档说明

For example, if keytool -genkeypair is called and the -keystore option isn’t specified, the default keystore file named .keystore is created in the user’s home directory if it doesn’t already exist

使用可视化工具KeyStore Explorer生成

除了keytool,我一般使用KeyStore Explorer直接点点点生成,毕竟各种命令太多也记不住,不如直接用鼠标点一点来的方便 KeyStore Explorer 中创建的密钥与证书条目

.pem文件和.p12文件的区别

见Stackoverflow > difference-between-pem-crt-key-files回答

PEM是一种文件格式,里面存储什么都可以。

在实践中,.pem文件通常代表此文件内容为公钥,而.p12文件内容通常代表此文件内容包括公钥和私钥和证书

为Tomcat配置TLS/SSL

Tomcat配置SSL的官方完整文档

配置SSL并使用自签名证书之后不生效

Tomcat重启之后,打开浏览器访问 https://localhost:8443/validation/,还是提示 浏览器访问本地 HTTPS 时显示证书不受信任的警告 对于自签名证书,我们需要将其导入到操作系统的指定位置

  1. 导出自签名证书
    keytool -export -alias tomcat -keystore .keystore -file tomcat.cer
  2. Mac OS中 > 钥匙串访问 > 将导出的证书拖到这里 > 双击证书 > 展开信任这一级 > 设置信任级别为始终信任 macOS 钥匙串访问中将自签名证书设为始终信任
  3. 设置完毕,重启Tomcat,HTTPS访问,发现Chrome这次提示不包含主备选名,但是Safari浏览器这次是正常的。

解决Chrome浏览器对自签名证书的不包含主备选名的问题

经过查找资料,对于自签名证书,要设置SubjectAlternativeName,

于是重新删除刚刚生成的key以及导出的证书,重新生成一次

keytool -genkey -alias tomcat -keyalg RSA -ext san=IP:127.0.0.1,DNS:localhost

关于san的写法完整说明,见keytool文档中supported named extension部分

生成完毕,再次导出证书、将其添加到操作系统的指定位置、信任该证书。再次重启Tomcat,再次访问https://localhost:8443/validation/ 浏览器访问本地 HTTPS 页面并显示安全连接信息 这次就是我们所期望的,看到了🔐标志

有了HTTPS后的世界

配置好HTTPS之后,我们再次尝试用WireShark抓包

这次我们请求的是https

curl -X POST -k https://localhost:8443/validation/valid/inline/post

WireShark抓到的包

tls and tcp.port in {8443, 55026}

Wireshark 中 HTTPS 报文仅显示加密的应用数据 可以看到,我们通过WireShark抓到的包都是加密的了,再也看不到裸奔的数据了。

还有一点值得注意的是,经过TLS加密之后是看不到整个HTTP请求的包括HTTP的URL等,对比一下文章最开始的那张图。

拓展思考-前端/客户端/浏览器端提交请求的时候加密有没有必要

这里说的前端加密是指提交登录请求的时候对用户输入的密码进行加密后再传给后端。这种讨论在各大技术网站上讨论很多,我只说下我的理解。

首先整个HTTP请求有三个地方有加密

  1. 客户端加密,也就是提交请求的时候加密
  2. 传输信道加密,就是HTTPS
  3. 服务端加密,稍微有些经验的开发都知道 存储密码会使用 hash(password + salt) 这种方式

假设是一个有点经验的开发,例如本人,已经知道服务端如何加密并了解HTTPS是对整个HTTP所有内容进行加密,那么对于该问题的回答是:我觉得前端加密没必要。

理由如下:

  1. 如果是在客户端提交请求的时候加密,其实防止不了浏览器中各种恶意插件里的脚本。直接监听你的键盘或者HTML元素即可,在你没提交请求前已经拿到了你的明文密码。
  2. 即使你的密码是拼在URL后面的,只要你的网站支持HTTPS,可以从上面看到,整个HTTP内容是加了密的,信道传输是安全的,可以忽略
  3. 很多大公司的登录也是明文提交,要不你先说服下他们的技术人才?

常见的争论:

  1. 如果我在输密码的时候,离开了电脑一会,这时有人偷偷摸摸来我这F12一下不就糟了?我想大多数人用前端加密的理由是这种场景。我觉得这种场景目前可以用2FA或Passkey来解决,如果你们公司无法支持该解决方案,那我觉得算了。因为这属于防君子不防小人,不再过多展开。
  2. 那前端的Request Body呢?有的网站F12打开Request Body是看不到的,有的是能看到的。这种的话,我认为是为了防止爬虫吧?如果被爬了,可以试试限流+黑名单之类的一些措施。本人在这方面经验较少,也不再展开。和上面的一样,防君子不防小人。

我的理解是,任何技术的实施都要看公司的技术团队人员配置以及技术栈掌握情况,成本,效益等等复杂的因素。

最后

本篇文章简单梳理了一下自己在理解TLS以及公钥、私钥以及CA证书等各个概念时疑问,以及思考。

下一篇将进行TLS握手详细分析

参考资料

  1. Java keytool文档,重点阅读Terms部分,这一部分介绍了各种概念,包括什么是keystore?什么是keystore的entry?什么是alias?什么是证书?什么是证书链?
  2. digicert的文章,什么是SSL/TLS?
  3. digicert的文章,什么是SSL证书?

分享本文:

继续阅读本系列

理解 HTTPS / TLS / SSL

  1. 理解HTTPS/TLS/SSL(一)基础概念+配置本地自签名证书正在阅读
  2. 理解HTTPS/TLS/SSL(二)可视化TLS握手过程并解密加密数据

评论

欢迎提问、纠错和分享经验。发表评论需要登录 GitHub;中英文版本共享评论。

评论仅在正式网站开放。