数字签名
数字签名可以解决数据安全里面的完整性,身份认证和不可否认三大特性,但是解决不了机密性问题。机密性需要通过对称密钥 / 公私钥解决,所以数字签名其实和加解密 / 密文 / 机密性这些在概念上非一个层次。
签名的本质不在于加解密,而是加验签。
数字签名,定义上是拿着私钥的一方,通过私钥 X 对消息 M 进行加密 (加签),生成签名 N,并把消息 M 和签名 N 一起给出去。拿着公钥的一方,用公钥 Y 对签名 N 进行解密 (验签) 生成 M’。用消息 M 和 M’ 做比较,如果相等,则数据没有被篡改。如果不想等,则数据不再安全。
对于公私钥,我们一般是使用公钥加密私钥解密,这样可以保障单向数据机密性。而私钥加密公钥解密是解决不了机密性问题的,如果要通过公私钥完全解决数据机密性,则需要双向认证。
数字签名就使用了私钥加密公钥解密这套方案,所以数字签名是没有密文 / 机密性可言的。在数据签名里,一般把私钥加密叫做加签,公钥解密叫做验签。
对称场景下摘要保障完整性
摘要和摘要算法就不解释了。摘要可以保障完整性,说的是对称加密场景下。
这里有一个疑问点,那就是对称加密场景下,数据本身已经安全了 (机密性)。即中间人无法解开信息,也就无法更改内容。这时候为什么还需要保障完整性?
这里说的对称加密,是排除密钥不安全的场景的。我们已经确定双方持有的对称密钥一定是安全的。这时候黑客虽然拿不到会话密钥,无法破解密文,但可以通过窃听收集到足够多的密文,再尝试着修改、重组后发给服务端。因为没有完整性保证,服务端会 “照单全收”,然后黑客就可以通过服务端的响应获取进一步的线索,最终就会破解出明文。
如果对称加密算法足够安全、对称密钥足够长、使用一次性对称密钥减少通信密文的数量,这些都可以进一步增加破解明文的时间。
但如果因为一些原因,没有上面的安全性保障,就有可能让黑客拿到足够多的样本,增加风险。这时候可以通过摘要来保障密文的篡改:
有了摘要保障完整性,服务端拿到数据后就可以校验一下,不符合完整性要求就可以直接拒绝服务了。
从这里可以看到,摘要就是原数据小且精确的数据替身。通过这个替身只能做到数据完整性校验,对于身份认证这些就做不了了。
实际上单纯在对称场景下,是无法保障数据安全的。因为最多只能做到机密性和完整性,而无法确定密钥的有效性,即身份认证和不可否认。
非对称场景下的摘要和数字签名
开头我们说到了数字签名的定义,从定义上可以看到,数字签名不依赖摘要。前面说到摘要是原数据小且精确的替身,既然是替身,那么数字签名就可以直接操作原数据避开摘要。
因为非对称加密的性能原因,公私钥对大数据的加解密是非常耗时的。有些数据可能达到几百 M 或者几个 G,用公私钥对这些原数据操作的代价是非常大的。
所以数字签名一般不直接对原数据进行加验签,而是通过摘要实现。数据签名并不一定非要使用摘要,但是一般都使用摘要。
1 | 性能原因主要发生在原数据过大的场景: |
数字签名流程如下:
和对称场景下的密文 / 机密性 / 完整性不同,数据签名只用于非对称场景下的明文数据。即:
1.(完整性)我给了你一份明文数据,这份数据虽然大家都可以看到,但我通过数据签名可以保障给你的数据一定是完整的,不会被其他人修改里面的内容,篡改了内容你肯定验签失败。
2.(身份认证)我还可以保障给你的这份数据一定是我给你的,因为你用我的公钥解开了数据,如果不是我亲自用私钥加签,你那边不可能解开数据,验签肯定失败。
3. (不可否认)而且以后我也否认不了本次交易的事实。因为基于完整性和身份认证两个前提,你拿到的数据一定是我亲自给你的有效数据。我无法否认本次交易的数据内容和本次交易的存在事实。
完成这套机制的核心就在于,私钥是非公开的。因为私钥的绝对安全和单一持有,保障了加签人和加签数据的唯一性。
这里说数据签名用于明文场景,是因为数据签名定义上,就是使用私钥进行加签。但加签的数据可以被所有公钥验签后获取,所以没有私密性可言。这也符合非对称加密的特点,即单向安全。数据签名正好使用的是反向,自然就没有密文一说了。
非对称加密只有在公钥加密私钥解密情况下才是安全的,这就是单向认证。如果希望双方的数据都是安全的,就需要使用双向认证了。
数字签名应用场景:PassKey
天下苦 登陆 & 验证码 久矣。
passkey 无密码登陆,是相当期待的功能。目前 Google 平台已经全面上线,Apple 和 微软 都已经对 passkey 做了支持。
无密码登陆,就是通过在终端如 iPhone/Android/Mac/Window 上,建立一份公私钥。
注册的时候,将终端私钥上传到服务端。
登陆的时候,服务端给一个校验字符串,让终端来加签。最后服务端用当初的公钥来解签。能解开并且和校验字符串一致,则表示当前用户值得信任。
https://www.passkeys.io/ 已经做了 passkey 注册的 demo,我体验了一遍,效果很棒。部分流程如下:
图中,是通过 iPhone 终端登录的。其实也可以通过 Mac 端直接登录,这样就可以少了换端的成本。
当通过其他端同步的时候,其实 chrome 浏览器是通过开启一个 socket 通道,使用中继服务器完成 passkey 的获取。
这里其实还有两个问题可以解答:
- 终端的公私钥,该怎么保存?这里 iPhone 会通过端侧加密和 iCloud 同步的方案,在 Apple 生态的机子上共享。还可以分享给他人。Android 等终端也都有差不多的能力。
- 终端如何确保不是他人来申请 passkey 能力?这里一般通过指纹和面部识别,也可以通过其他硬件辅助验证。
下面是整套 passkey 注册和登录的流程图:


数字签名应用场景:SSL (2025.01.18 更)
在 7 层网络协议里,SSL 分为握手协议和记录协议,分别处于表示层和会话层,主要负责网络数据的传输安全。
从对称场景下的摘要可以知道,对称场景下是没有身份认证的,这样就会使得密钥存疑。如果 A 和 B 通信的密钥被 C 给更换了,那么 C 就可以假冒 B 与 A 通信。所以 HTTP 退出了历史舞台。
非对称加密的双向认证是可以解决这个问题,但因为非对称加密耗时厉害,没有被有效的采用。所以就有了通过数字签名来传输公钥,通过单向安全性把临时对称密钥给到对方,而后双方使用对称密钥通信的策略。这就是 HTTPS (SSL/TSL) 使用的方案。
HTTPS 的安全核心在于对称密钥 (或者种子) 的安全传输。根据非对称加密单向安全性,只要拥有公钥的一方生成对称密钥并把密钥通过公钥加密给到另一方,拥有私钥的对方才可以解开数据并拿到密钥,这样就安全传输了。
而数据签名之所以能传递有效的公钥,就是因为它具有完整性、身份认证、不可否认的特点。拿到的公钥,一定是安全的公钥,如果被动了手脚,一定会被发现。
SSL 证书格式
SSL 证书,是一个二进制文件或者 base64 文件,包含源信息(公钥、网站名称、有效期等)和数字签名(背书机构通过其私钥对源信息进行的签名)。
其中,每个 SSL pem 证书包含的公钥是当前证书管理者的公钥,数字签名是上级证书管理者对当前证书的签名。
对于用户申请的 SSL 证书(向中间 CA 机构申请)pem 格式,一般包含以下几个部分:
- 证书信息:包含证书的有效期、颁发机构、域名、签名算法等
- 公钥:当前用户网站 / 域名的公钥(私钥也只有当前用户知晓,保存于用户的服务器,用于后续的 https 对称通信密钥的生成)
- 数字签名:中间 CA 机构私钥对当前源信息(证书信息 + 公钥 + Other)进行加签后生成的签名,用于验证当前证书完整性
SSL 证书是通过证书链来进行验证的,下一级证书(中间 CA)的信息如下:
- 证书信息:包含证书的有效期、颁发机构、签名算法等
- 公钥:中间 CA 机构的公钥
- 数字签名:根 CA 机构私钥对当前源信息 (中间 CA 证书) 进行加签后生成的签名,用于验证当前证书完整性
根 CA 证书信息如下:
- 证书信息:包含证书的有效期、颁发机构、签名算法等
- 公钥:根 CA 机构的公钥
- 数字签名:根 CA 机构私钥对当前源信息 (根 CA 证书) 进行加签后生成的签名,用于验证当前证书完整性
证书链
在具有安全效益的证书中,都是采用【证书链】机制的。即每一个【终端证书】,都是通过【根证书】或者【中间证书】签发的(层层签发)。
比如 A 网站,它向 M 中间 CA 机构申请 SSL 证书的时候,机构会提供证书链供下载,包括【A 终端证书】、【M 中间证书】和【根证书】。
用户 T 访问 A 访问的时候,服务器返回的 pem 会包含【A 终端证书】、【M 中间证书】,一般不用返回根证书,因为用户的电脑里面有【根证书】,这是信任链的源头。
证书链验证流程:
正向解析证书链
浏览器根据 A 证书、M 证书,分析出 根证书,从而确定证书链:A -> M -> 本机根证书
逆向验证证书链
- 默认相信本机根证书,这是信任的源头
- 浏览器根据本机根证书里面的公钥,验证 M 证书是否有效
a. 浏览器验证 M 证书有效期等信息是否合法
b. 浏览器根据 M 证书的签名算法规则,对【源信息】生成【摘要】
c. 浏览器根据根证书的公钥,对 M 证书里面的签名进行解签,得到【解签后的摘要】
d. 比较【源信息摘要】和【解签后的摘要】是否一致。若一致,则 M 证书有效。提取 M 证书里面的公钥进入下一层使用。 - 浏览器根据 M 证书里面的公钥,验证 A 证书是否有效
a. 浏览器验证 A 证书有效期等信息是否合法
b. 浏览器根据 A 证书的签名算法规则,对【源信息】生成【摘要】
c. 浏览器根据上一层验证拿到的 M 证书的公钥,对 A 证书里面的签名进行解签,得到【解签后的摘要】
d. 比较【源信息摘要】和【解签后的摘要】是否一致。若一致,则 A 证书有效。提取 A 证书里面的公钥进入下一层使用。 - 验证 A 证书有效后,后续的 HTTPS 通信就可以使用 A 证书里面的公钥来生成对称密钥了。
特别说明 - 交叉验证
证书链的验证是一个链条过程,只要有一环验证失败,整个链条就会失败。这就需要根 CA 预先存储于本机中。
一般来说,操作系统和浏览器,都会主动的更新本机的根 CA 证书,但如果本机真的没有根 CA 证书,就会影响到证书链的验证。
比如 Google 在 2017 年也成为根 CA 发行机构,那就有可能出现一些机器本机根本没有 Google 的根证书,那么它发行的中间 CA 证书就无法验证了。
Google 根证书:GTS Root R4, Google 中间证书:WE1, a.com 证书: A
有一种交叉验证的方式,即 这里的 WE1 证书,不仅仅可以通过 GTS Root R4 根证书加签,还可能通过其他根证书加签(确保本机已经存在的根证书)。
这样,虽然本机没有 GTS Root R4 根证书,但是通过其他根证书,也可以验证 WE1 证书的有效性,进一步验证 A 证书的有效性。
自签名证书
对于非 CA 机构签发的用于自行测试的【自签名证书】,有两种方案:
- 先生成自签名的【根证书】,而后通过【自签名根证书】来生成所有的【终端证书】
- 直接生成【终端证书】
采用方案一的话,直接把【自签名根证书】导入用户设备并信任,后续所有的【终端证书】都能够使用了,通常用在企业内部或者测试场景。
数字签名应用场景:SSH
SSH 全称 Secure Shell
,即 “安全壳协议 “。SSH 突破安全枷锁的方式和 SSL 是一样的,相比来说少了证书链校验
这个环节,即 Client 和 Service 需要自行保障公钥的可靠。
具体来说很直接,就是如果 Client 需要登陆 Service,第一次登陆的时候 SSH 工具会提示 Service 的公钥,人们需要看下这个公钥和 Service 那边公开的公钥是否一致。一致后 Client 侧会做公钥缓存,后面就不会再提示了。
其他的都和 HTTPS 是一样的了,通过公私钥确认对称密钥,通过对称密钥进行数据安全传输。
数字签名应用场景:iPhone App
iPhone 的 ipa 包,有非常多的安装限制,都是通过数字签名来控制的。Apple 使用的双重认证方案,即开发者和 Apple 公司同时提供公私钥签名,来使得 ipa 包不会被滥用和滥安装。
总结
数字签名是通过私钥加签,所有公钥都能验签,所以没有机密性可言。数字签名实现了完整性、身份认证、不可否认,而机密性则是通过对称加密 / 非对称加密来完成密文保障。
数字签名,是数据安全的基石。