文章目录
  1. 1. 历史
    1. 1.1. 隐藏信息
    2. 1.2. 加密信息
  2. 2. 现代
    1. 2.1. 对称加密
    2. 2.2. 非对称加密
    3. 2.3. 散列算法
  3. 3. 协议
    1. 3.1. SSL/TLS
    2. 3.2. HTTP/HTTPS
  4. 4. CA及证书
    1. 4.1. 数字证书
    2. 4.2. 信任链
    3. 4.3. 申请证书
  5. 5. 动手时间
    1. 5.1. 加解密
    2. 5.2. 散列
    3. 5.3. 证书
  6. 6. 参考资料

现在网络这么发达,许多人都在上面购物、理财、预约挂号…网络上传送的可都是自己的重要资料,比如身份证号,信用卡密码等。因特网如何才能保证这些敏感信息的安全?本文试着来探讨一下加密、证书等那些事儿。

历史

隐藏信息

古代交通不便,一般都是通过送信的方式传递信息。那么如何保证信件的内容不被泄露呢?一种方法是隐藏字迹。中国古代使用矾书,也就是用明矾水来书写保密书信。水干之后没有任何痕迹,泡水时字才显示。还有一招是使用淀粉水在纸上写字,再把纸泡在碘水中显示字迹。据知乎的水波说在西方世界里,也有使用牛奶或者羊奶书写信息,待干掉以后再用高温烘烤使之重新显现字迹的说法。这些办法一旦为人所知,便会轻易被破解,而且还有点儿此地无银三百两的意思。

加密信息

除了隐藏信息以外,还有加密的方法。在宋代兵书《武经总要》里,约定了40个常用的军事短语,送信内容为一首40个字的五言律诗,每个字代表一个军事短语。然后在相应的字上做标记,对方就明白了,这个叫字验。这个就有点儿密码表的意思了。从知乎某匿名用户的回答上找了一张图:

在西方世界里,古希腊军队将长条羊皮纸缠绕在约定长度和粗细的木棍上书写,木棍称为Scytale。把羊皮纸解下来后就变成没有意义的字母了。古罗马的凯撒大帝用的是字母移位的办法。比如有封信写着:IFMMP,多半我们是不知道啥意思的。要是对方事先说明了把每个字母都右移一位的方法,也就是A变成B,B变成C…Z变成A,那我们就能很轻松地把IFMMP变成HELLO,明白对方的意思。

现代

对称加密

对上文说的凯撒大帝移位法而言,“右移”就是算法(algorithm),一位的“1”就是密钥(key)。计算机普及后,最早的有影响力的算法是DES(Data Encryption Standard),它的秘钥是64位,但只有56位会用来计算。所以,只要最多尝试256(大约是七万亿)次的暴力破解,就能解密。随着计算机硬件的发展,这个数量级在1998年只要56小时就能破解,到了1999年变成了24小时以内。这样就不够安全了。于是四年之后,AES(Advanced Encryption Standard)取代了DES成为了新的标准。它可以使用128、192或256位密钥。最低的128位也能承受大约三千万亿亿次的暴力破解,至少目前看起来还算是比较安全的。在DES向AES的过渡期间,使用了3DES算法。所谓3DES,可以理解成重要的事情做三遍,用不同密钥的DES加密三次,几乎也就等同于56×3=168位的密钥,这样也算是比较安全了。

非对称加密

对称密钥有一个问题,就是密钥通过什么渠道来传输。加密算法再好,密钥被偷走了,也无济于事。在这样的背景下,非对称加密问世了。它的密钥包含着一个公钥和一个私钥。私钥顾名思义是只有你自己的电脑才知道的,公钥是公开的。用私钥加密的数据只有用公钥才能解开,同样的,用公钥加密的数据只有用私钥才能解开。假如两台电脑甲和乙相互通信,双方先把自己的公钥告诉对方。当甲给乙发消息时,用乙的公钥来加密,由于只有乙有相对应的私钥,所以只有乙能解密,甲要是忘记了消息内容连自己都解不了,更遑论第三方了。反之亦然。非对称加密最常用的算法是RSA(发明者Rivest、Shmir和Adleman的姓氏首字母)。它的私钥和公钥是通过至少百位的大质数来生成的。由于在数学上很难计算大整数的因数,所以目前来说是比较安全的。万一哪天数学或量子计算机上有了突破,这种算法也就不再可靠了。1999年,512位的RSA被成功分解。2009年,768位的RSA也被成功分解。现在通用的1024位密钥可能也不那么可靠了,从安全的角度来说应该升级到2048位或以上。密钥这么大,非对称加密的速度比较慢(与对称加密有千倍的差距)也是可以理解的。所以在实际的使用当中一般用对称加密来加密数据,非对称加密来加密对称加密的密钥。

散列算法

好吧,密码破解不了,但是攻击者可以截取加密后的数据包,然后篡改。这样“传位十四皇子”就变成了“传位于四皇子”啦。散列算法堵死了这条路。它能把很长的数据变成固定长度的文本。也称为数据的摘要(digest)或指纹(fingerprint)。相同数据的摘要一定是一样的,不同数据的摘要有可能一样,但是通常不一样。正因如此,散列算法是不可逆的,也就是说不能从数据摘要倒推出数据来。但是它可以用来校验数据是否被更改。如果数据有变化,那么摘要通常都是不一样的,概率取决于散列的长度,越长越不容易相同。配合上文所说的非对称加密,如果我用自己的私钥加密了某个摘要,那它就只有用我的公钥才能解密。这就说明了这个摘要一定是我发出的,因为别人不可能有我的私钥。进而推导出摘要所代表的消息也是由我发出的。这个加了密的摘要称为数字签名(Digital signature)。它保证数据的完整性,确定数据的发出者,是具有法律效力的。

原来常用的散列算法有MD5SHA1,2004年后,山东大学的王小云教授通过碰撞法分别攻破了这两种算法。也就是说,在已知摘要的情况下,可以很快计算出另一个拥有相同摘要的文本,这样就实现了文本篡改。行话叫散列碰撞(Hash Collision)。所以NSA推出了SHA2SHA3成为了新的标准。虽然MD5和SHA1被破解,也不用特别在意。因为虽然能找到相同摘要的数据,但是篡改者并不能随心所欲地把数据修改成自己想要的样子。

协议

SSL/TLS

有了加密算法,是不是传输就安全了呢?确实如果严格去用的话,是安全了,但是也麻烦了很多。每次都要跟对方沟通用什么算法,传送密钥,传送摘要…累不累?所以需要有一套协议,大家都遵守这样的协议,就能少掉很多我们不需要太关注的、技术上的事情。这个协议叫做SSL(Secure Sockets Layer)。它所做的事情,主要就是上面说的交换公钥,用对方的公钥加密数据,用自己的私钥解密,还支持MD5用于验证数据的完整性。SSL是网景公司发明的,由于应用广泛,成为了事实上的标准。IETF(Internet Engineering Task Force)在1999年把SSL 3.0标准化,称为TLS(Transport Layer Security)。除了标准化以外,相对SSL来说TLS也更加安全一些。

HTTP/HTTPS

因特网发明后,大部分的网站都是用的HTTP协议。这个协议关心的是如何方便地获取到自己需要的资源,并不关心安全性。如果你的网络被监视(比如你的wifi提供者,运营商等等),对方是可以明文看到你的所有信息的,行话叫嗅探(sniffer)。在HTTP上应用SSL/TLS的协议叫做HTTPS(HTTP over SSL/TLS)。有了它,我们就还可以像以前的HTTP那样方便地在网上冲浪,而不用太担心安全问题,但不是完全不需要担心,一会儿我们会说到。

顺便说一句,SSL/TLS并不是只能用于HTTP,还可以用于FTP(File Transfer Protocol)、SMTP(Simple Mail Transfer Protocol)等一系列应用层协议。

CA及证书

数字证书

前面说到了HTTPS,为什么有了这么安全的技术我们还是不能高枕无忧呢?这是因为:虽然它能保证我们的信息不被第三方破解,但是它绕不开一个很现实的绕口问题:你怎么知道他就是他声称的那个他?举个栗子:你以为正在访问的网站是某个银行,但是却不知道其实你被钓鱼(phishing)了。对方正等着你输入你的银行卡号和密码,好用它们去真正的银行网站给自己转账。这一切发生得这么自然,你的信息只有钓鱼网站能解密看到,钓鱼网站的信息也只有你能解密看到…就算是你注意到了对方的域名,也有可能因为0和O、1和l傻傻分不清楚或者域名劫持(domain hijacking)而上当。数字证书就是用来阻止这事儿发生的。虽然我不认识你,但是如果我认识一个很知名的家伙,他肯为你做担保,那我也可以相信你。这个知名的家伙就叫CA(Certificate Authority)。它为通信的双方起了一个中间人的作用。CA的担保就叫数字证书(Digital Certificate或Public Key Certificate)。这个证书是什么格式,有什么内容呢?这是由PKI(Public Key Infrastructure)标准决定的。常用的标准有X.509PKCS #12。它们定义了证书里应该含有签发机构名、证书用户名、有效期、算法、公钥等信息。

信任链

回到刚才的问题:你怎么知道他就是他声称的那个他?我无条件地信任CA,网站又有了CA的数字证书,我就能信任他就是证书里声称的那个他。如果我因为对CA的信任而有了损失,则证书可以用来追究CA的法律责任。如果我们信任A,A信任B,B信任C,那么我们也会信任B和C,这个叫做证书信任链(Chain of trust)。中间的B称为中级证书(Intermediate certificate),位于信任链顶端的A称为根证书(Root certificate)。如果根证书出了问题,那么它所信任的其它证书也就不再可信了。这个后果可是非常严重,可能会影响整个因特网的信任体系。所以,需要尽可能地少动用根证书以减少根证书的私钥被盗用的风险。如果网站想要被认证,直接用中级证书认证就好了。万一中级证书出问题,吊销掉中级证书也只会影响一部分客户,比整个根证书被吊销掉强。但事情也不绝对。对CA来说,公信力就是一切。说个案例:中国互联网络信息中心(China Internet Network Information Center,CNNIC)是中国的顶级域名.cn和中文域名的注册管理机构。MCS集团用CNNIC签发的中级证书,发行了多个冒充成Google的假证书。于是在2015年4月份,chrome、firefox都宣布不再信任CNNIC的证书。如果你用chrome来打开https://www.cnnic.net.cn/,应该会看到:

而不是:

一般来说操作系统和浏览器都会内置一些信任的CA,比较著名的有公信力的CA有Verisign,GeoTrust等。我们打开google的时候,也能点击小锁看到它的证书:

再点击证书信息就能看到它的证书链。最上面的是GeoTrust的根证书,它包含的内容都在里面写着了,感兴趣的话就自己看看吧:

中间的是谷歌自己的中级证书:

最后是站点自己的证书,这个有效期一般比较短:

证书是可以自签名的,也就是说,你自己作为CA来发行这个证书。当然,这个证书也只有你自己会信任,广大的网友同志们的眼睛是雪亮的,不会无缘无故地信任你的。那如果我是大企业,是不是就值得信任了?谷歌、微软等通常都是可以信任的。12306,你信任它吗?每个人都会有自己的答案吧。打开12306看看它的根证书,SRCA(SinoRail Certification Authority)是个什么鬼?这个是中国铁路自己啊。知道为什么首页上总有一个“为保障您顺畅购票,请下载安装根证书”的提示了吧。

申请证书

首先,如果你觉得自己的网站没有什么信息不能公开的,那就没必要费那钱和时间去购买证书。

证书有很多种类型,价格也很不一样,大约一年数千到数万元人民币吧。简单列出几种:

  • 通配符证书(Wildcard SSL Certificates):自己的域名和下一级子域名可以使用。比如google.commaps.google.com就是域名和二级子域名的关系
  • 多域名证书(Subject Alternative Name SSL Certificates):不仅限于子域名,不同域名也能使用
  • 增强型证书(Extended Validation SSL Certificate):总之就是验证流程更麻烦,结果就是可以在地址栏显示公司的名称,增加可信度。就像这样:

申请证书需要给CA提供一个CSR(certificate sigining request)文件。通常做法就是通过程序把域名、联系人和公钥等信息都放在这个文件里,发送给某个CA。交费之后,如果CA方面没有问题,就会对CSR文件设置有效期等操作,当然还需要用自己的私钥对证书签名,再发送给用户。最后用户把证书绑定到自己的网站上。

动手时间

加解密

OpenSSL是SSL/TLS的开源实现,我们就用它来练练手吧。首先,用DES加解密文本:

1
2
echo Hello World! | openssl enc -e -des -a ## 需要输入两次密码,如果你输入的都是1,那么可以用下一条命令解密
echo U2FsdGVkX19NMXhTRoTNJE0YV+TKcRL0+xzT9UMUN5Y= | openssl enc -d -des -a

其中的-a代表base64编码。还可以多试几次加密,就算文本、密码相同,每次加密的结果也很可能是不一样的。把上面的-des变成-des3或者是-aes-256-cbc就可以自行尝试DES3和AES加解密了。接下来尝试RSA。首先生成RSA的私钥:

1
2
openssl genrsa -out private.pem 2048
cat private.pem

PEM表示这是base64编码的密钥,也可以改成DER即二进制的密钥,加上一个-outform DER的参数就行。然后通过私钥生成公钥:

1
2
openssl rsa -in private.pem -pubout -out public.pem
cat public.pem

接下来用刚刚生成的公钥加密,私钥解密:

1
2
3
echo Hello World! | openssl rsautl -encrypt -pubin -inkey public.pem -out encrypt
cat encrypt
cat encrypt | openssl rsautl -decrypt -inkey private.pem

然后私钥加密,公钥解密。注意这个的意义其实是私钥签名,公钥认证:

1
2
3
echo Hello World! | openssl rsautl -sign -inkey private.pem -out encrypt
cat encrypt
cat encrypt | openssl rsautl -verify -pubin -inkey public.pem

散列

现在轮到散列算法了:

1
2
echo Hello World! | openssl dgst -md5
echo Hello World! | openssl dgst -sha1

也可以用linux自带的小工具实现:

1
2
3
4
5
6
echo Hello World! | md5sum
echo Hello World! | sha1sum
echo Hello World! | sha224sum
echo Hello World! | sha256sum
echo Hello World! | sha384sum
echo Hello World! | sha512sum

是不是越来越长了?散列越长越不容易被碰撞。

证书

申请证书,首先需要生成CSR文件。而CSR文件需要先生成私钥:

1
2
3
openssl genrsa -out private.pem 2048
openssl req -new -key private.pem -out domain.csr
cat domain.csr

生成私钥文件是可以加密的,加上一个参数比如-des3就可以了。生成CSR文件的时候需要填写各种信息,没耐心就随便写点什么甚至一路回车也行,反正又不是真的去找CA。如果你真的有需求,这里有一张表格说明了应该怎么填。填完的东西可以这么看:

1
openssl req -noout -text -in domain.csr

现在我们假装自己是个CA,有自己的密钥对,然后对刚才提交的CSR文件签名:

1
2
3
openssl genrsa -out private_ca.pem 2048
openssl x509 -req -days 365 -in domain.csr -signkey private_ca.pem -out my_domain.crt
cat my_domain.crt

大功告成!生成的my_domain.crt就是我们要的证书。由于这个是自签名证书,默认是不被我们的操作系统信任的。如果我们需要增加信任,可以参考这里。比如在Ubuntu/Debian里可以这么做:

1
2
sudo cp my_domain.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates

如果要取消信任,可以这么做:

1
2
sudo rm /usr/local/share/ca-certificates/my_domain.crt
sudo update-ca-certificates --fresh

参考资料

How Encryption Works
有关SSL证书的一些事儿
SSL/TLS原理详解
OpenSSL 与 SSL 数字证书概念贴
数字证书及 CA 的扫盲介绍
扫盲 HTTPS 和 SSL/TLS 协议
数字签名是什么?
CNNIC证书值得信任吗?

文章目录
  1. 1. 历史
    1. 1.1. 隐藏信息
    2. 1.2. 加密信息
  2. 2. 现代
    1. 2.1. 对称加密
    2. 2.2. 非对称加密
    3. 2.3. 散列算法
  3. 3. 协议
    1. 3.1. SSL/TLS
    2. 3.2. HTTP/HTTPS
  4. 4. CA及证书
    1. 4.1. 数字证书
    2. 4.2. 信任链
    3. 4.3. 申请证书
  5. 5. 动手时间
    1. 5.1. 加解密
    2. 5.2. 散列
    3. 5.3. 证书
  6. 6. 参考资料