网络安全——对称加密,数字签名,非对称加密以及HTTPS
前言
Alice and Bob are fictional characters commonly used as placeholders in discussions about cryptographic systems and protocols, and in other science and engineering literature where there are several participants in a thought experiment. The Alice and Bob characters were invented by Ron Rivest, Adi Shamir, and Leonard Adleman in their 1978 paper "A Method for Obtaining Digital Signatures and Public-key Cryptosystems".——Alice and Bob - 维基百科
本文按照惯例以 Alice 和 Bob 作为通信两端的代名词,在必要时,还会引入第三者 Trudy. 读者也可以自行代入到张三李四王五.
对称加密
通信双方Alice、Bob都事先持有相同的密钥key、加密算法encrypt、解密算法decrypt.
- Alice使用密钥
key和encrypt加密明文message,得到密文ciphertext - 而Bob收到密文
ciphertext后,使用key和解密算法decrypt得到明文message
对称加密的一个前提是,通信双方都事先知道密钥,并保证不能被第三者知道,在现实中,Alice和Bob可以约在咖啡店约定通信密钥. 而在网络通信中,通信双方是不透明的,Bob无法验证收到的数据来自于Alice而不是中间人Trudy.
因此,在网络通信中,对称加密面临通信双方如何安全地共享密钥的问题.
散列函数与摘要
散列函数通常使用AES或MD5,它们对相同的输入产生相同的输出,在输出空间足够大的情况下,碰撞的可能性极小. 通常,使用散列来计算数据的摘要,用以确定唯一性.
MAC(Message Authentication Code)
如果把散列函数应用到Bob与Alice的通信中,就可以实现,传输过程中,一方发出的数据即使被篡改,另一方可以感知:
- Bob通过散列函数H对明文m计算摘要得到H(m),记为h,并将报文与摘要(m,h)一起发送给Alice.
- Alice对报文m再次计算摘要得到h2,比较h与h2是否相等,从而判断报文m是否被修改或丢失.
上面的过程问题在于,散列函数是公开的,如果中间人Trudy截获了Bob发给Alice的(m,h),并将其替换为(m2,h2),Alice收到后无法感知报文已被替换.
由于报文m与散列函数H都是公开的,需要引入一个私有的分量,鉴别密钥(authentication key),来使得报文摘要无法被伪造,通常这个由「报文+鉴别密钥」产生的摘要被称为鉴别码(Message Authentication Code,MAC). 例如,假设Bob和Alice都提前商定一个密钥s,
- Bob使用H(m+s)作为鉴别码,发送(m,H(m+s))给Alice.
- Alice使用相同的方式 H(m+s)来计算摘要,并与接受到的摘要做对比,从而判断报文是否被篡改.
这个通信过程中,中间人Trudy即使截获了Bob发出的(m,H(m+s)), 但由于不知道鉴别密钥s, 因此无法在修改m后,伪造一个可以通过验证的鉴别码.
但是,MAC保证完整性的前提是,通信双方可以安全的共享鉴别密钥,这就面临与对称加密相同的问题. 在双方不透明的因特网中,Bob如何确定与自己商定密钥的一定是Alice,而不是Trudy呢?
非对称加密
从凯撒密码时代到20世纪70年代的两千多年以来,加密通信都都需要双方共享一个共同秘密. 直到20世纪70年,由于计算机网络的高速发展,人们对密码学也提出了更高的要求. 回顾上文中描述的对称加密(机密性)、MAC(完整性),它们都存在一个待解决的问题,如何在网络中鉴别与自己商定密钥的另一方的身份.
非对称加密的出现,解决了这一问题. 第一个非对称算法由Diffie和Hellman在1976年提出. 而使用最为广泛的算法是RSA,该算法取名字 Ron Rivest、Adi Shamir 和Leonard Adleman的首字母命名.
非对称加密算法中包含两把密钥K+和K-,K+加密的密文只有K-才能解密,而反过来K-加密的密文则只有K+能解密. 由于非对称加密通常会把其中一把密钥直接或间接公开(比如各类软件包的下载页会公开自己的公钥和软件包的签名),所以这两把密钥也被称为公钥、私钥
比如apache tomcat的 public key、signature
数字签名
非对称加密的一个典型应用就是数字签名,在现实生活中,「签名」被应用到很多场景中,比如签订合同、法律文件,甚至小学生的作业. 签名具有两个特征:
- 可鉴别,签名可以确定一个唯一的通信对象.
- 不可伪造,第三方无法生成.
前文讲过的MAC不能满足第一点,由于使用对称加密,Alice和Bob都持有相同密钥,能产生特定MAC的对象不唯一. 因此,MAC不适合用作数字签名.
数字签名(digital signature)使用非对称加密,Bob的私钥是自己独有的,而公钥任何人都可以得到. 每当Bob要签名一个报文时,使用自己的私钥对报文通过加密算法得到一个加密的串作为签名. 任何人都可以使用Bob的公钥通过解密算法验证报文是否来自于Bob. 由于非对称加密算法的计算量较大,在签名时,通常会先求出明文的hash,再使用私钥对这个hash计算签名.
双向安全通信
摘要可以验证消息完整性,数字签名可以验证发送者身份,会话密钥(对称加密)则保证了报文的机密性,将三者综合则可实现安全通信.
如下是一个实现了双向安全通信的案例,该案例中,Alice、Bob都需要验证对方的身份,因此Alice、Bob各有一对非对称密钥,用作数字签名. 由于非对称密钥并不适合加密报文,因此选择对称密钥KS来作为会话密钥.
- Alice的非对称密钥: KA+、KA-
- Bob的非对称密钥: KB+、KB-
- 会话密钥: KS
上面的案例假设了Alice 和 Bob 事先知道对方公钥,此时只要黑客没有入侵他们的本地系统调包公钥,那么通信就是安全的. 而网络中通信双方并不总是提前持有对方的公钥,比如Alice访问淘宝、知乎、微博...等非常多的服务端,Alice不可能事先知道这些站点服务器的公钥, 这些站点更不可能持有Alice的公钥. 于是,如何在网络中安全地传输公钥就成为一个迫切的问题. 而解决办法就是引入第三方权威机构进行公钥认证.
公钥认证
数字签名解决了身份鉴定的问题,但这仍旧基于一个前提: 验证的一方需要事先持有被验证的一方的公钥. 而在网络通信中,通常不具备这种条件. 设想一个较坏的情况,这种场景下,Bob持有自己的私钥、公钥,另一方Alice没有Bob的公钥,因此,Bob需要在网络中传输公钥给Alice.
- Alice发送一个请求给Bob,希望得到Bob的公钥,以便建立「安全的」通信.
- Bob发送公钥给Alice, 但是不幸被中间人Trudy截获,Trudy把Bob的公钥替换为了自己的公钥.
- Alice收到了被调包的公钥,以为这是Bob的公钥,并用该公钥加密自己的报文发送给Bob
- 中间人Trudy截获Alice的报文,并用自己的私钥解密报文. 至此,Trudy获得了Alice/Bob不希望公开的信息,而通信双方对这一切并不知情.
SSH登陆与上述场景相似,Bob代表了ssh服务端,Alice代表了希望登陆Bob的客户端, 为了防止服务端的公钥被中间人调包,客户端在第一次登陆时会让用户通过肉眼方式确认Bob的公钥指纹.
至此,你会发现,现在面临的核心问题是:"如何安全的传输公钥?" ,更确切的说是: "如何鉴定网络中传输的公钥的真伪?". 在上例中,Alice需要一种方式去认证收到公钥到底是Bob的,还是中间人Trundy的.
因特网中,认证身份这一职责由专门的机构来完成,这些机构被称为认证中心(Certification Authority,CA), CA通过给申请者颁发证书,来将申请者的身份与证书绑定,
- 身份,可以是一个人,一个公司,一个站点,甚至一台路由器
- 证书,包含申请者的公钥和身份的描述
具体来讲,CA拥有一对非对称密钥,其中私钥由机构自己独有,而公钥则是共开的,操作系统会内置受信任的CA公钥.
申请者拿着自己的公钥、以及身份,向CA申请证书. CA通过一些方式鉴定申请者是否具有该身份,
比如笔者在给域名light0x00.com申请SSL证书时,就被要求给自己的域名添加一个特定的CNAME解析,该地址必须是可访问的,通过这种方式证明我是该域名的所有者.
如果鉴定通过,则颁发给申请者一个X.509格式的证书,证书中包含几个重要的信息:
- 签名,由CA的私钥对证书的摘要计算得出
- 申请者的公钥,以及身份信息
了解一些背景,现在回到我们的例子,Bob向CA申请了证书,而Alice则拥有CA的公钥
-
Alice对Bob发起通信请求,Bob返回自己的证书(该证书包含CA签名)
-
Alice收到这个「暂不明确来源的证书」,对其做如下鉴定:
- 通过CA公钥解密Bob的证书的签名,如果签名是伪造的,那么解密这一步会失败.(CA身份鉴别)
- 经过上一步,可以得到CA的签名中的证书摘要h1,使用相同的散列函数对证书求得摘要h2,通过比对即可知是否被篡改过(完整性)
- 经过上面两步,至少可以证明证书确实出自受信任的CA,接下来,只需要鉴定证书中的信息是否表明这是Bob的证书.(如果是Bob的证书,那么就应该有Bob的申请时填入的信息,比如Bob的名字、邮箱、电话等) (对等方身份鉴别)
如果上述鉴定都通过,则表明,证书中的公钥确实是Bob的,而不是中间人Trundy. Alice可以放心的使用这个(Bob的)公钥加密想要发送的信息.
这里存在一个逻辑误区,你也许会觉得,Bob的证书是公开的(在传输时),既然是公共的,那么中间人Trudy也能得到这个证书,看似Trudy可以做点坏事,比如可 Trudy截获Bob原本发给Alice的证书,这时她有如下选择:
- 调包证书,这会使得Alice的鉴定过程中的第3步无法通过.
- 不调包证书,这样不能有任何作为,因为Alice会拿Bob证书中的公钥加密, 而Trudy没有Bob的私钥,无法解密数据.
- 修改证书,比如把证书中的Bob姓名改为Frank(不图啥,就做个恶作剧),而这会使得Alice的鉴定过程中的第2步失败,因为证书内容变了,这样摘要也变了,无法匹配签名中的摘要.
- 修改证书的签名,这会使得Alice的鉴定过程中的第1步无法通过.
重放攻击
使用了前文的种种安全措施,看起来通信的安全性已经固若金汤了,但仍旧存在一些问题.
目前可以保证
- 可鉴别,中间人无法伪造身份
- 完整性,中间人无法修改、伪造报文
- 机密性,中间人无法看到明文
顺带一提,中间人是可以阻止通信的(不然也太没面子了吧),比如丢弃报文、或在Tcp层面Reset连接、或物理隔离(切断通信设施).
但中间人仍有其他选择,比如,可以将截获的报文,重复发送给接收方,这种攻击称为重放攻击. 对一些不幂等的通信报文,比如Bob向在网上执行一个转账动作,该动作从Bob的账户扣除100,并在另一个账户增加100,这个动作有副作用(side effect)的,执行一次与两次造成截然不同的结果. 假如中间人对该报文作重放,将使得Bob的账户被洗劫一空.
吐个槽,这种典型的接口幂等性应该由应用程序开发者去解决.
在传输层,TCP协议使用序列号(Seq)来解决相似的问题,一个连接中,如果一方收到一个Seq=0的TCP报文段,则其维护的Ack+1,后续若再次收到Seq=0的报文段则会被丢弃.
借鉴TCP的思想,在应用层,通过引入一个不重数来参与会话密钥的产生,使得每一次会话都使用不同的密钥,可以保证会话内报文的有效性. 具体来讲,如果中间人用上一次会话的报文在新的会话中重放,则接收方可以感知这是一个无效的报文,因为会话密钥已经更新.
HTTPS
HTTPS 是前文所提到的所有安全措施的综合应用. 在使用 HTTPS 前,网站所有者需要制作证书让 CA机构用CA私钥签名; 而客户端一方,则需事先在系统中内置CA机构的公钥.
申请证书 网站维护者生成一对密钥,包含公钥和私钥,将公钥和域名以及一些额外信息打包制作成 CSR(Certificate Signing Request)文件,提交给CA认证中心进行审核。在审核通过后(主要验证域名是否属于申请者),CA会依据CSR文件制作证书,并对证书签名:
- 使用hash函数对CA证书的原始内容计算摘要.
- 使用CA私钥加密摘要和原始内容,作为数字签名(digit signature)
密钥对、证书通常使用OpenSSL生成,其中公钥与填写的信息打包一个CSR文件中. 关于CSR制作
部署证书 在得到证书后,将证书(cert文件)部署到服务器,通过对web服务器做一定配置,如监听443端口,并指定key(私钥)、cert(ca证书)的路径.
客户端
操作系统自身维护了CA的公钥.
TLS握手(Transport Layer Security Handshake)
客户端使用https初次访问站点时,除了TCP层面的3次握手,还需要在应用层通过TLS握手来确定 身份鉴定、会话密钥 为了完成这一过程,C/S之间需要进行3次通信:
-
Client Hello,客户端让服务端返回证书,并确认一下非对称加密算法、对称加密算法(保证机密性),和MAC算法(保证完整性的)
由于非对称算法性能消耗较大,所以仅用于数字签名,对报文的加密是用对称加密.
-
Server Hello,服务端返回证书(里面包含服务器的公钥),并告知后续通信的MAC算法、非对称加密算法、对称加密算法(决定双方如何生成会话密钥)
-
Change Cipher Spec,客户端使用 CA 公钥验证该证书,只有 CA 公钥验证通过,并且证书中的信息,如域名与当前访问的域名一致,那么就说明证书不是伪造的,进而里面的服务端公钥也是真实的,客户端就可以用这个公钥加密会话密钥,发给服务端.
证书是用 CA 私钥签名的,而 CA 公钥内置于操作系统中,所以可以验证证书内的信息是否伪造.
纵观上述过程,CA 起到了至关重要的作用,
- 网站所有者把自己的(公钥+域名)拿去让 CA机构用 CA 私钥签名.
- 在客户端访问网站服务器时,服务端返回自己的证书.
- 客户端用 CA 公钥(内置在客户端系统中)去验证返回的证书的签名是否伪造,如果是真实的,那么就取出里面的服务端公钥,用这个公钥去加密后续通信的会话密钥.
更进一步提炼,CA保证了证书的可鉴别性、不可伪造性,进而保证了证书中服务端公钥的真实性,而服务端公钥则可保证了会话密钥的机密性,因为只有"服务端私钥"持有者才能解密出会话密钥.
TLS握手最终保证了会话密钥只有通信双方知道, 这也就解决了前文提出的一个问题:
现实中 Alice 和 Bob 可以约在咖啡馆确定密钥,而网络中由于中间人的存在让双方无法直接传输密钥.
参考
- 《计算机网络自顶向下法》