TSL 证书
TSL 证书
CA 证书
CA 证书是什么,证书的本质实际上就是 CA 用 CA 自己的私钥对服务器申请证书的时候提交的服务器的公钥、服务器的域名以及所属单位这些信息的签名进行加密,从而保证信息无法被篡改。
为什么无法被篡改,因为一旦证书内容(比如公钥,比如 IP)被篡改,重新签名之后,就会跟之前加密的签名对不上,客户端就会察觉,那我把签名也更换了不就好了,不行,因为客户端会用 CA 的公钥来对加密的签名进行解密,如果无法解密,说明这个证书不是 CA 签发的,也是无法被信任的。
CA 根据以下流程生成证书:
- 生成证书内容。包括:
- 公钥(想要签发证书的申请证书的时候需要把服务器的公钥发给 CA,详细解析请看 ssh_ca#证书登录的流程)
- 申请者的身份信息(如域名)
- 证书的有效期
- 证书序列号等
- 签名证书,CA 使用自己的私钥对证书内容进行签名,生成数字签名。
- 签名过程:使用哈希算法计算证书内容的摘要,并用 CA 的私钥加密摘要。
- 签名验证:任何人可以使用 CA 的公钥验证签名的有效性,确保证书未被篡改。
我们在 https#HTTPS 的通信过程 中了解过,服务端将服务器证书发送到客户端之后,客户端需要校验证书的有效性,此时就需要 CA 签发服务器证书的公钥,那客户端从哪儿获取 CA 的公钥呢?答案是客户端操作系统或浏览器中预装了信任的 CA 根证书,其中包含 CA 的公钥。这样客户端用 CA 的公钥验证服务器证书上的数字签名,确保证书是由可信 CA 签发的且未被篡改。
自签名证书
我们有时候会在浏览器地址栏上看到 https 证书不可信
,意思其实就是,服务器发给客户端也就是浏览器发的证书不是来自 ca,我们无法保证这个证书不是来自于中间人攻击。
大部分的时候,尤其是在离线环境下,为了避免申请 CA 证书的麻烦,我们都会使用自签名证书。
CA 证书跟自签名证书的区别
ca 证书就是服务器把自己的公钥发到 CA 然后 CA 用自己的私钥来对你发过来的信息(包含公钥)的签名进行加密,详细过程过程请看 ssh_ca#证书登录的流程。
而自签名证书就是服务器的公钥不发到 CA 了,直接就在用自己的私钥来对签名进行加密,所以叫自签名。
就是一个用哪个私钥给签名进行加密的区别,除此之外自签名证书的内容和权威 CA 签发的证书基本相同
通过 OpenSSL 进行自签名证书
参考博客 中的脚本在生成私钥的时候加了密码,其实没有必要,我们可以不对私钥进行加密。
local_ip=127.0.0.1
openssl genpkey -algorithm RSA -out private.key
echo -e "CN\nWH\nWC\nHW\nTX\n${local_ip}\n\n\n" | openssl req -new -key private.key -out ssl.csr
# 生成一个有效期为 365 天的证书
openssl x509 -req -days 365 -in ssl.csr -signkey private.key -out public.crt
第一步指定本地 IP,因为证书是跟 IP 地址绑定的
第二步则是生成密钥,这里为了方便我们就不指定密码了,不然后面只要用到了这个私钥都得输入密码,非常不方便。
openssl req
这个命令是一个交互式命令,我们先输入一个信息,点击回车之后再输入第二个信息,输入完所有信息命令就执行结束。我们为了跳过这个交互过程方便我们一键执行,我们就需要把所有的输入都通过 echo+ 管道传递给命令,但是我发现分多次 echo 没有用(即echo "A" | echo "A" | openssl req
),只能把所有的输入和回车一次 echo 给openssl req
,通过文件重定向也能实现类似的效果:openssl req < command.txt
。
具体跳过交互式命令,请看 用脚本实现交互式命令的输入
第三步则是准备生成证书的请求,将这些请求包装成一个文件,有点类似于填写表单。
第四步就是提交请求,生成证书。
经过上面这几步,证书文件就是 public.crt
,私钥就是 private.key
。
通过 nginx 可以轻松为端口配置 ssl,请看 nginxTips#通过 Nginx 将 HTTP 请求变成 HTTPS,其中 ssl.crt 为 ssl_certificate,ssl.key.unsecure 为 ssl_certificate_key
客户端校验自签名证书的过程
浏览器验证自签名证书时,会依次检查以下内容:
- 证书是否可信:浏览器会检查证书的签发者(Issuer)是否在其信任存储(Trusted Root Store)中。对于自签名证书,签发者是自己,因此证书需要手动导入到操作系统或浏览器的信任存储中。如果证书未被信任,浏览器会提示“不安全”或“证书无效”。
- 签名验证:浏览器使用证书中的公钥验证证书的数字签名。如果验证成功,说明证书内容未被篡改。对于自签名证书,签名的验证者和签发者是同一个实体。
- 域名匹配:浏览器会检查证书中的域名(CN 或 SAN 字段)是否与访问的 URL 匹配。如果不匹配,则会提示“证书名称无效”。
- 证书有效期:检查当前时间是否在证书的有效期内。如果证书已过期或尚未生效,会提示“证书已过期”或“证书无效”。
CA 签发证书到了浏览器之后,浏览器本身也有 CA 的这个签名私钥对应的公钥,所以经过签名校验可以保证这个公钥就是 CA 签发的公钥。
自签名的证书到了浏览器,用 CA 的公钥无法验证签名,但是证书里的公钥依然是可以直接使用的,也就是说依然可以生成对称加密密钥,进行加密通信。也就是说,使用自签名的证书依然可以走完完整的 TSL 握手流程,生成对称加密密钥,只是我们不能保证这个过程不被中间人攻击,在我们进行业务开发的时候,往往通信的双方就是浏览器和服务器,不用担心中间人攻击,此时我们就可以使用自签名密钥,来验证 HTTPS 协议的可行性。
浏览器不信任自签名证书的原因
- 证书未被信任:未手动导入到信任存储。
- 证书名称不匹配:域名或 IP 地址与证书中的 CN/SAN 不符。
- 证书过期:证书的有效期不正确或已过期。
- 自签名证书的签名错误:生成证书时的签名过程不正确。
如何为自签名证书添加信任
由于自签名证书不被浏览器默认信任,用户需要手动将其添加为可信证书,以下是具体步骤:
- 在操作系统中导入
- 下载自签名证书文件(通常是 .crt 或 .pem 格式)。
- 打开操作系统的证书管理工具:
- Windows:运行 certmgr.msc。
- MacOS:使用“钥匙串访问”(Keychain Access)。
- Linux:将证书添加到
/etc/ssl/certs/
或浏览器的信任存储。
- 将证书导入到“受信任的根证书颁发机构”存储中。
- 在浏览器中导入
- Chrome/Edge:
- 进入“设置 > 安全性与隐私 > 管理证书”。
- 导入自签名证书到信任的根存储区。
- Firefox(独立的证书存储):
- 进入“设置 > 隐私与安全 > 证书 > 查看证书”。
- 导入证书并勾选“信任此证书用于识别网站”。
- Chrome/Edge:
通过命令行请求 HTTPS
我们可以直接用 curl 的 -k
参数跳过 TSL 证书的验证