自建数字签名证书
Abstract Keywords 数字签名证书 Let’s Encrypt证书 SSL证书 数字签名证书 Let’s Encrypt证书 SSL证书
Citation Yao Qing-sheng.自建数字签名证书.FUTURE & CIVILIZATION Natural/Social Philosophy & Infomation Sciences,20240808. https://yaoqs.github.io/20240808/zi-jian-shu-zi-qian-ming-zheng-shu/
局域网内搭建浏览器可信任的SSL证书[1]
首先是为什么要干这个事情,你可能会说随便搞个自签名证书难道不能用吗?答案是还真的不能用,的确对于开发来说搞个自签名的证书就行了。但是一旦放到生产环境浏览器对证书有效性进行验证的时候便是不可信状态,这时就必须要用户点击一下继续访问,但是对于我们即将实施项目的自动化要求来说没法这样干。你可能又会说了现在这个环境在阿里云、华为云这些平台上随便申请一个免费的证书难道不行吗?答案是真的不行,因为项目的特殊要求最终我们部署的环境是完全没有外网访问的,就只能在局域网环境下运行及意味着不光是SSL
证书的问题我们连DNS服务器都要自己建。这时候你可能又要说了那么直接用http
访问就可以了,干嘛要用ssl
证书呀?答案是这个项目需要使用WebRTC
进行音视频多人会议,而WebRTC只能在https
下运行。
其实上面的说法有一个点需要更正一下,自签名证书其实也可以但是一旦对超过100个客户端进行分发简直是要命的事情,所以我们通过Windows域控的方式统一对下属计算机进行证书分发保证可用性。
※1.原理
SSL证书的信任机制其实是非常简单的,第一需要一个机构证书,第二是需要服务端证书,一般来说机构证书被称为CA证书,而服务端证书就称为服务器证书吧。那么为啥https
非常安全呢?答案其实不复杂,下面就是一段逻辑性描述来说明为啥https
是安全的。
通常情况下我们在给Nginx、Tomcat、IIS上配置的证书便是服务器证书,那么它是怎么保证客户端访问的地址绝对没有被拦截修改的呢?其实也不复杂,当我们的浏览器发起一个请求的时候到服务端上时,对应web服务器会通过证书的秘钥将http响应值进行一次加密,然后将密文与明文同时返回出来,客户端浏览器接收到响应之后会将密文对称解码然后和明文进行对比,这样一来便可以保证响应值没有被串改。
这个时候逻辑上稍微厉害一点都会发现一个问题,客户端是怎么解码的?这里的答案就是服务端在响应的时候同时会将证书的公钥也返回,这个公钥只能解码对应私钥加密的信息,同时这个公钥无法加密只能解密,这样一来如果如果某人想要拦截http请求便必须知道对应的私钥才行,否则浏览器一旦发现解密信息对不上便知道了响应数据已经被拦截修改过了。
如果你反应过来了你会发现一个新的问题,那么假设拦截这自己搞了一对有效的私钥和公钥然后伪装为服务器不就行了,恭喜你盲生发现了华点。这里就需要CA证书来处理了。其实服务器证书的公钥是由CA证书的秘钥配对加密来的,这样一来当请求返回的服务器公钥和通过CA证书进行验证时便会发现这个公钥是不是由机构签发的公钥,一旦对应不上则说明服务器不是原来CA证书签发服务器证书,这就证明你的请求被第三方拦截了。同时CA证书对于浏览器而言只有公钥,也就是说安装证书时本质上就是将CA证书的公钥导入到你的电脑上了,至此除开CA机构的证书发放者没有知道CA证书的秘钥是什么这样一来便可以保证下面几个非常关键的安全性:
- 你请求的服务绝对是官方的服务器,绝对不是黑客自建的服务器。
- 服务器响应给你的数据绝对是正确的,期间黑客绝对无法对其进行修改。
证书的结构如下:
这里还有一个问题便是这些CA证书是哪来的,自己的电脑上又重来没有导入过什么证书。这里便是一个非常无耻躺着赚钱的商业模式了,微软、谷歌、苹果等公司提供了操作系统和浏览器,他们便是第一方的CA机构,他们的系统自己肯定信任自己对吧?所以系统安装的时候他们的CA公钥已经安装到你们的系统里面了,然后这几家巨头合伙说那么这些CA公钥在每种系统都有,然后就是一写第三方公司和这些巨头打成了合作,这些公司的机构证书也被巨头们信任所以理所当然的入库了,这些三方机构便是大名鼎鼎的Symantec
、GeoTrust
几个巨头,这些机构一个单域名的签名证书都敢直接拿出来卖,一年好几千,对他们而言无法就是给下发的证书进行一次签名而已,真正的躺着赚钱。
※2.开始制作证书
这里我使用的证书工具是openssl
,经典工具,坦白的说非常难用。
※2.1创建CA证书
首先第一步肯定是制作一个机构证书也就是CA证书出来,这里有两种方案,第一是直接用openssl
创建CA证书,另一种是windows域控生成域组织的CA证书,我们分开说。
※2.1.1通过openssl
创建CA证书
第一步是创建一个秘钥,这个便是CA证书的根本,之后所有的东西都来自这个秘钥:
1 | # 通过rsa算法生成2048位长度的秘钥 |
第二步是通过秘钥加密机构信息形成公钥:
1 | # 公钥包含了机构信息,在输入下面的指令之后会有一系列的信息输入,这些信息便是机构信息,公司名称地址什么的 |
这一步需要输入的机构信息有点,分别说一下:
参数名称 | 参数值 |
---|---|
Country Name | 国家代码,比如中国就是CN |
State or Province Name | 省名称 |
Locality Name | 城市名称 |
Organization Name | 机构名称 |
Organizational Unit Name | 机构单位名称 |
Common Name | 重点参数:授权给什么,因为机构是根节点所以是授权给自己 |
Email Address | 邮件地址 |
※2.1.2通过windows域控创建CA证书
这种便是我采用的方案,执行上比直接用openssl
创建证书复杂多了,但是好处也非常多,一方面域控下级的所有计算机天然对域控服务就是信任状态,第二是域控制器能够通过组策略域内同步CA证书,本质上来讲相对于多了一个CA证书同步与分发的机制。我这边使用的Windows Server 2016,其他版本区别也不大。
第一步是在域控上启用证书服务
第二步是安装完毕之后配置证书
这里非常简单,我都不想说了,直接根据提示输入相关信息就行了,在过期时间那一步最好将时间拉长,我还是使用的100年。
第三步是通过组策略进行分发
策略路径是:计算机策略/Windows设置/安全设置/公钥策略/受信任的根证书颁发机构
和计算机策略/Windows设置/安全设置/公钥策略/受信任的发布者证书
。将上面创建的证书导出之后,在这里导入即可。
※2.2创建服务器证书
在得到CA证书之后,需要通过openssl
工具对证书进行转换得到公钥(.crt文件
)和密钥(.key文件
),无论CA证书是怎么来的到这里之后就没有任何区别了,服务器证书的制作流程相较CA证书要复杂一点点。
第一步通过openssl
工具创建服务器的秘钥:
1 | # 通过RSA算法生成长度2048位的秘钥 |
第二步这里是创建一个签名请求
需要将服务器信息写入到请求文件之中,然后通过CA机构证书对请求签名形成服务器证书公钥,这一步要复杂一些,很多网上的教程在这里都GG了主要原因没有把原理搞清楚。
首先https
证书的公钥不同于自定义情况下的加密证书,这里需要安装浏览器标准进行配置,首先openssl
默认的证书版本是V1,V1在支持https
时部分浏览器依旧会认为不安全,所以需要使用V3版本;同时openssl
即便是使用V3版本依旧没有附带V3的subjectAltName
字段数据(这里是证书对应的IP地址或者域名,可以用通配符)。但是这些东西命令行没法指定所以需要配置文件,我这里准备了一个:
1 | # openssl.cnf |
将上面的配置内容保存为openssl.cnf
放到生成的服务器证书文件的目录下(注意:修改alt_names里面的域名或者IP为最终部署需要的地址,支持通配符),然后执行创建签名申请文件即可,执行运行:
1 | # 和创建CA时一样这里需要输入一堆服务器信息,输入项也是相同的。 |
PS:上述配置文件使用sha1算法生产的证书,部分浏览器已经已经不信任该算法了,如果你使用的时候遇到sha1相关的问题,可以参考评论区的kevin同学提供的方案。
如果你遇到sha1问题,用稍微新一点的openssl.cnf文件 https://github.com/openssl/openssl/blob/master/apps/openssl.cnf
同时还要在这个文件里稍微改一下,把下述的配置加入进去
1
2
3
4
5
6
7 [ v3_req ]
subjectAltName = @alt_names
# 这里是重点,需要将里面配置为最终服务端需要的域名或者IP
# 这里可以写多个,能够自行添加DNS.X = XXXXXX
[ alt_names ]
DNS.1 = xunshi.com
DNS.2 = *.xunshi.com加上。
最后用请求生成密钥的时候 用下面这个指令 使用sha384代替默认的sha1openssl x509 -req -extfile openssl.cnf -extensions v3_req -in server.req -out server.cer -CAkey myCA.key -CA myCA.cer -sha384 -days 36500 -CAcreateserial -CAserial serial
第三步通过CA机构证书对服务器证书进行签名认证
1 | # 这里没有什么需要说的,本质上就是将签名请求文件进行签名最终得到服务器的公钥 |
第四步部署证书
这里应该没有什么需要说的了,我们通过Nginx部署,最终得到server.key
就是秘钥,server.cer
文件就是公钥只需要配置给Nginx就行了。
※3.信任CA机构证书
如果通过Windows域控创建的CA证书,其证书本身通过组策略便可以给每一个域下计算机添加机构信任。如果你没有域控只是通过openssl
创建的CA证书也没有关系,只需要将CA证书的公钥(myCA.cer文件
)导入到系统信任的根证书颁发机构里面就行了:
这个界面在windows的internet选型->内容->证书
可以打开,导入即可,也可以直接双击cer
文件进行证书安装,最终不光是windows系统,任何操作系统都可以安装证书来进行对CA机构的进行信任操作。
在对证书进行信任之后通过https打开浏览器进入内网DNS
或者host
配置的域名便可以得到没有任何警告的内容的安全连接:
如果是Mac系统访问逻辑也是一样的通过安装CA证书并且在钥匙串内添加信任之后依然可以正常访问:
在Android手机上也是一样,安装并且信任证书之后可以正常访问:
※4.总结
本来对我对https
的认证逻辑其实理解没有多深入,以前也只是用过SSL证书进行TCP传输加密而已,经过对openssl
的学习现在至少在理解上达到了及格水平,不过这次学习论证与探索的过程我个人极其不愉快,本来这东西在有了理解之后大家都看得出来不是什么很难的东西,事实上我也只用了一天半就搞定了。但是网上充斥大量垃圾内容,不光没有什么正向内容甚至不少内容还TM起了误导的作用,整个中文互联网检索体系下就没有找到一篇文章稍微详细描述整个搭建逻辑与流程,简直了,最终我只能从https
原理和openssl
的官方文档开始看起,过于离谱了。基本上可以得到一个结论现在天天写一些所谓干货的博主简直就是滥竽充数,其内容千篇一律大多数也是抄袭来的基本上什么都没有说清楚简直浪费时间。
最后说一下https
的原理,在解释清楚之后其实不是绝对上的安全,结合本文各位可以想一下怎样去伪造一个页面出来?假设我是黑客来搞入侵其实只需要一个小小的脚本就可以了,我们自行制作CA和服务证书之后,通过修改HOST文件对域名解析进行劫持将其引导到我们自己的服务器,然后将我们自己制作CA证书注入目标电脑的受信任证书组,这样一来对于被入侵者已经看到是安全连接但是其请求已经被我们拦截了。所以各位不要看到https就以为安全了,一旦你的电脑本身就被入侵了那么https
也是形同虚设的,所以在执行高风险操作的时候最好还是点开站点的证书看看对应的CA机构是不是被修改过。
免费的Let’s Encrypt证书[2]
一个比较离谱的事情发生了,我每年在阿里云搞得免费证书现在有效期只有3个月,相当于我TM每三个月就要去手动更新一下证书,之前的博客也写了SSL这个东西简直就是一本万利的事情(局域网内搭建浏览器可信任的SSL证书),这种完全不能忍,所以拜拜了资本家,老子不用你了,免费证书不香吗?
Let’s Encrypt就是免费证书的代表,这玩意几乎所有设备都支持,并且能申请通配证书,步骤如下:
※安装snapd,这是为了安装certbot的工具
1 | yum install snapd |
※安装certbot,这个工具就是拿来申请证书的
1 | snap install --classic certbot |
※申请证书
1 | certbot certonly --manual --preferred-challenges dns |
- 在运行这个命令之后会开始证书的申请步骤,具体如下:
- 如果需要提供邮箱就按照提示输入邮箱即可;
- 按照提示输出域名,用空格分隔多个域名
- 注意:tangyuecan.com和www.tangyuecan.com是两个不同的域名,如果使用通配域名就是*.tangyuecan.com
- 通过提示进行DNS验证,这里按照要求添加一个TXT解析即可
- 注意:连续超过5次解析失败,服务器在未来五个小时都无法继续申请
- 成功之后就会生成对应的证书文件;
※使用证书
certbot 生成的证书文件很多,其中对于nginx等常规的web server就只有两个有用:
- fullchain.pem:这个是证书文件,兼容大部分web server;
- privkey.pem:这个是秘钥文件;
以nginx为例,最终使用证书配置如下:
1 | server { |
※自动更新证书
没有想到吧,还有这个功能,原理也很简单,但是使用上存在一个问题,每一次更新的证书的时候都需要对域名所有权进行一次校验,只有通过了校验Let’s Encrypt才会知道这个域名是你在管理,进而才会为你更新证书,上文使用DNS进行验证的话,运行renew进行重新校验可能是没法通过的,因为certbot无法访问你的DNS解析对吧,所以这里最佳方案是通过web服务器进行验证。
1 | certbot certonly --webroot -w /var/www/example -d www.example.com -d example.com --dry-run |
特别注意:如果你使用了泛域名解析就不能直接通过webroot进行更新证书,毕竟泛域名不大可能指向同一个webroot路径,这种情况下想要实现自动更新证书只有通过DNS插件才能实现,可以参考这个项目

Address:Department of Natural/Social Philosophy & Infomation Sciences, CHINA
Biography...
转载或引用本文时请遵守许可协议,注明出处、不得用于商业用途!
Like this article? Support the author with