HTTPS

一 HTTPS是什么?
维基百科对HTTPS的解释:
超文本传输安全协议:是一种通过计算机网络进行安全通信的传输协议。HTTPS经由HTTP进行通信,但利用SSL/TLS来加密数据包。HTTPS开发的主要目的,是提供对网站服务器的身份认证,保护交换数据的隐私与完整性。这个协议由网景公司在1994首次提出 随后扩展到互联网上。
抓重点:HTTPS=HTTP over SSL/TLS,也就是说,HTTPS在传输层TCP和应用层HTTP之间,多走了一层SSL/TLS
在这里插入图片描述
The SSL/TLS protocol functions between two layers of the OSI Presentation layer.The handshake and record layers operate over TCP/IP to encrypt data received directly from the Application layer
SSL/TLS协议作用在传输层和应用层之间,对应用层数据进行加密传输
在这里插入图片描述
HTTPS 应运而生,
它被公认的三大优势有:
1.数据加密,防窃听
对称加密:前者只有一把秘钥做加解密
对称加密是最快速、最简单的一种加密方式,加密(encryption)与解密(decryption)用的是同样的密钥(secret key)。对称加密有很多种算法,由于它效率很高,所以被广泛使用在很多加密协议的核心当中。
对称加密通常使用的是相对较小的密钥,一般小于256 bit。因为密钥越大,加密越强,但加密与解密的过程越慢。如果你只用1 bit来做这个密钥,那黑客们可以先试着用0来解密,不行的话就再用1解;但如果你的密钥有1 MB大,黑客们可能永远也无法破解,但加密和解密的过程要花费很长的时间。密钥的大小既要照顾到安全性,也要照顾到效率,是一个trade-off。
Rijndael算法:
private string myData = “hello”;
private string myPassword = “OpenSesame”;
private byte[] cipherText;
private byte[] salt = { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0 };

    private void mnuSymmetricEncryption_Click(object sender, RoutedEventArgs e)
    {
        var key = new Rfc2898DeriveBytes(myPassword, salt);
        // Encrypt the data.
        var algorithm = new RijndaelManaged();
        algorithm.Key = key.GetBytes(16);
        algorithm.IV = key.GetBytes(16);
        var sourceBytes = new System.Text.UnicodeEncoding().GetBytes(myData);
        using (var sourceStream = new MemoryStream(sourceBytes))
        using (var destinationStream = new MemoryStream())
        using (var crypto = new CryptoStream(sourceStream, algorithm.CreateEncryptor(), CryptoStreamMode.Read))
        {
            moveBytes(crypto, destinationStream);
            cipherText = destinationStream.ToArray();
        }
        MessageBox.Show(String.Format("Data:{0}{1}Encrypted and Encoded:{2}", myData, Environment.NewLine, Convert.ToBase64String(cipherText)));
    }
    private void moveBytes(Stream source, Stream dest)
    {
        byte[] bytes = new byte[2048];
        var count = source.Read(bytes, 0, bytes.Length);
        while (0 != count)
        {
            dest.Write(bytes, 0, count);
            count = source.Read(bytes, 0, bytes.Length);
        }
    }

解密过程:
private void mnuSymmetricDecryption_Click(object sender, RoutedEventArgs e)
{
if (cipherText == null)
{
MessageBox.Show(“Encrypt Data First!”);
return;
}
var key = new Rfc2898DeriveBytes(myPassword, salt);
// Try to decrypt, thus showing it can be round-tripped.
var algorithm = new RijndaelManaged();
algorithm.Key = key.GetBytes(16);
algorithm.IV = key.GetBytes(16);
using (var sourceStream = new MemoryStream(cipherText))
using (var destinationStream = new MemoryStream())
using (var crypto = new CryptoStream(sourceStream, algorithm.CreateDecryptor(), CryptoStreamMode.Read))
{
moveBytes(crypto, destinationStream);
var decryptedBytes = destinationStream.ToArray();
var decryptedMessage = new UnicodeEncoding().GetString(
decryptedBytes);
MessageBox.Show(decryptedMessage);
}
}
HTTPS对称加密的秘钥sk如何产生和传播
HTTPS分为两个过程:
1 协商对称加密秘钥sk 的非对称加密阶段 称之为TLS握手阶段
2 使用SK对数据进行加密阶段 称之为数据通信阶段
过程 1TLS 握手阶段:协商密钥 SK。网上关于这个知识点的文章有很多,然而一些已经过时,一些则不全。就协商密钥 SK 这块,笔者推荐《扫盲 HTTPS 和 SSL/TLS 协议[3]:密钥交换(密钥协商)算法及其原理》和《密钥协商机制》。本文直接扔出结论,HTTPS 协商对称加密密钥 SK 的办法有很多种,介绍 3 种较为常见的办法:

基于非对称加密算法
基于专用密钥交换算法,常见有 DH、ECDH 等
在这里插入图片描述
基于共享的 secret,常见有 PSK,SRP 等

非对称加密:两把秘钥,公钥和私钥,互为加解密,公钥给对方,私钥自己用,HTTPS两者都有。
在这里插入图片描述
客户端给服务端发送请求;

服务端返回客户端自己的公钥 PuK;

客户端产生本次对话的对称密钥 SK,并用 PuK 进行加密得到 SK_Enc 后传给服务端;

服务端收到 SK_Enc 后用自己的私钥 PrK 解密得到 SK;若成功,则返回客户端 OK,否则终止对话.

接下来,客户端和服务端的对话均用 SK 加密后传输。
目前最常用的非对称加密算法是RSA算法
加密过程:
private byte[] rsaCipherText;
private void mnuAsymmetricEncryption_Click(object sender, RoutedEventArgs e)
{
var rsa = 1;
// Encrypt the data.
var cspParms = new CspParameters(rsa);
cspParms.Flags = CspProviderFlags.UseMachineKeyStore;
cspParms.KeyContainerName = “My Keys”;
var algorithm = new RSACryptoServiceProvider(cspParms);
var sourceBytes = new UnicodeEncoding().GetBytes(myData);
rsaCipherText = algorithm.Encrypt(sourceBytes, true);
MessageBox.Show(String.Format(“Data: {0}{1}Encrypted and Encoded: {2}”,
myData, Environment.NewLine,
Convert.ToBase64String(rsaCipherText)));
}
解密过程:
private void mnuAsymmetricDecryption_Click(object sender, RoutedEventArgs e)
{
if(rsaCipherText==null)
{
MessageBox.Show(“Encrypt First!”);
return;
}
var rsa = 1;
// decrypt the data.
var cspParms = new CspParameters(rsa);
cspParms.Flags = CspProviderFlags.UseMachineKeyStore;
cspParms.KeyContainerName = “My Keys”;
var algorithm = new RSACryptoServiceProvider(cspParms);
var unencrypted = algorithm.Decrypt(rsaCipherText, true);
MessageBox.Show(new UnicodeEncoding().GetString(unencrypted));
}
总结
(1) 对称加密加密与解密使用的是同样的密钥,所以速度快,但由于需要将密钥在网络传输,所以安全性不高。
(2) 非对称加密使用了一对密钥,公钥与私钥,所以安全性高,但加密与解密速度慢。
(3) 解决的办法是将对称加密的密钥使用非对称加密的公钥进行加密,然后发送出去,接收方使用私钥进行解密得到对称加密的密钥,然后双方可以使用对称加密来进行沟通。

2 身份验证 防冒充
3.1 证书是什么?
解释这个问题之前,先看几个关键词:CA,CA 机构,数字证书,数字签名,(证书)指纹,(CA)证书,HTTPS 证书,SSL/TLS 证书。

理一理上面这些关键词之间的关系:

CA,CA 机构:机构/组织概念。

数字证书,(CA)证书,HTTPS 证书,SSL/TLS 证书:CA 签发的数字证书。

数字签名,(证书)指纹:CA 签发的证书的内容之一,一段加密的密文。

智库百科对数字证书的解释是:

数字证书也称公开密钥证书,是指用于电子信息活动中电子文件行为主体的验证和证明,并可实现电子文件保密性和完整性的电子数据。数字证书是一个经证书认证中心(Certification Authority,简称 CA)发行的文件。
数字证书包含有行为主体信息和证书认证机构的数字签名。数字签名是指以电子形式存在,可依附在电子文件中用于辨识电子文件的签署者及表示对该电子文件内容负责所使用的电子数字标识。
抓重点:
首先,数字证书=主体信息+数字签名。
数字证书用于主体身份验证。

在这里插入图片描述在这里插入图片描述
主体的必要信息:版本(version)、序列号(serialNumber)、签名算法(signatureAlgorithm)、颁发者(issuer)、有效期(validity)、使用者(subject)、公钥信息(subjectPublicKeyInfo)

主体的扩展信息(extension):如密钥标识符、证书策略等

数字签名(signature),也称指纹
抽象为
在这里插入图片描述
3 完整性校验 防篡改
HTTPS 已经对通信数据进行了加密,为什么还要验证身份?说好的“人与人之间最基本的信任呢?”

这还不是因为各路黑客、骇客们总是在制造各种攻击吗?(捂脸)其中一个大名鼎鼎的中间人攻击(Man-In-The-Middle Attack,MITM 攻击),简单的讲,“中间人”在客户端和服务端都不知情的情况下,夹在双方之间窃听甚至篡改通信信息,过程见下图(图引自《HTTPS 中间人攻击实践(原理·实践)》):
在这里插入图片描述
在 HTTPS 的握手阶段,一端向对端发送请求,对端返回自己的公钥;而一端未验证对方的身份和公钥,直接协商密钥。“中间人”看到了这个漏洞,夹在中间截获了对端的公钥,替换成了自己的公钥。正是这步“拿错了公钥”或者说“信错了对端”,使得 HTTPS 为加密(密钥协商的非对称加密和通信数据的对称加密)所做的努力全部泡汤。

可见,在 HTTPS 中,“确保对端身份正确”即“确保拿到的公钥正确”,而在网络通信中所谓的“身份”,一般指的是通信一端的域名、IP 地址甚至是Mac 地址。所以,数字证书同时包含了通信一端的身份信息和公钥信息。

但是数字证书会在网络中传输(由被要求验证身份的一端通过网络传给另一端),这就意味着证书也可能会被窃取篡改。这个时候权威的 CA 机构就出马了,他想了个办法:加了一个“防伪标识”— 数字签名。具体做法如下:

signature = RSA(PriKey_CA, Hash(message))
这里啰嗦几句:数字签名生成过程是首先对原文作哈希,把一段不定长的文本映射成固定长度的字符空间,接着再用 CA 机构的私钥对这段定长字符做加密。大大提高了整体的运算效率。

3.3 证书是怎么工作的?
要了解证书是怎么做“身份验证”,即“防冒充”,得从 2 个角度来说明:

申请证书,即需要被验证身份的一端,需要申请一份能够验证自己身份的证书

验证证书,即需要验证对方身份的一端,拿到证书后验证对端的身份

请注意,这里有一个前提:这张证书必须是由权威 CA 机构颁发的,且尚在有效期内;或者是一张信任的私人证书。

申请证书

CA 机构和证书的分类本文不讨论,推荐阅读《细说 CA 和证书》,这里我们讨论正规权威 CA 机构签发的证书,至于是 DV、OV 还是 EV,只是安全强度问题,工作原理是一样的。

总结申请证书的过程:用户向 CA 机构提交自己的信息(如域名)和公钥(用户自己生成的非对称加密公钥,用于 TLS 握手阶段和另一端协商密钥用),CA 机构生成数字证书,如下图:
在这里插入图片描述
在这里插入图片描述
接受证书的一端先对除数签名的其他部分做一次相同的哈希算法(证书中指明了哈希算法),得到这段文本的哈希映射,记作 H1;获取 CA 机构的公钥对数字签名属性做解码,得到了 CA 机构计算出的哈希映射,记作 H2。对比 H1 和 H2 两个字符串是否严格相等,若是,代表该证书的信息未被篡改,证书有效;否则,证书内容被篡改,证书无效。

若证书有效,接受端会再进行对端的身份校验(验证域名),若身份验证通过,接收端会拿证书上的公钥(也是对端自己生产的非对称加密公钥)加密接下来整个 TLS 握手阶段的信息之后,发送给对端。

这个过程中有一个问题:CA 机构的公钥怎么获取?

回答:提前内置。

众所周知,操作系统和浏览器在软件安装阶段会在其特定目录下放置一堆的证书。如 Windows 的根证书管理在 certmgr 下:

这些证书都有个特点:权威 CA 机构发布的根证书(Root Certificate)。根证书有几个特点:

没有上层机构再为其本身作数字签名

证书上的公钥即为 CA 机构发布的公钥

权威 CA 机构的自签证书

而这些根证书会跟很多软件,包括操作系统、浏览器一起被安装到用户设备上。即使没有被提前安装好,这些根证书也可以在 CA 机构的官网上获取得到。

目前全球大型权威 CA 机构有 Symantec、GeoTrust、Comodo 以及 RapidSSL 等,并且这些机构颁发的 SSL 数字证书,在市场的占有率是非常的高。(节选自《SSL 证书颁发机构有哪些》)

本地被内置了这么多的根证书,那要怎么知道我这份证书应该要用哪一个根证书来验证呢?

回答:证书信任链。

在信任链上有 3 类证书:根证书,中介证书和用户证书。根证书前文已有说明,用户证书就是对端发过来的证书,或者说是用户向权威 CA 机构绑定了自己身份(主要指域名)和自己公钥的证书。中介证书可以理解由权威 CA 机构委派的代理机构签发的数字证书,推荐阅读《What is an intermediate certificate?》。中介证书或者说是中介机构的存在是为了保证根证书的密钥的安全性。

细心的同学仔细看一看 certmgr 会发现有一个分类是“中间证书颁发机构”,这里存放的就是中介证书。用户证书绝大多数是通过权威的 CA 机构的代理中介机构颁发。

这么来说,根据对端发来的用户证书寻找对应的根证书岂不是更困难了?

自问自答:这是一个在树形数据结构中,从叶子节点搜索根节点的过程,直接一个最原始的深搜(DFS)不就可以了嘛?举例说明,如下图(引自Wikipedia-Chain of trust):
在这里插入图片描述
从用户证书开始。

记“Issuer”字段的值为 i1,搜索本地证书,寻找由“Subject”为 i1 的证书。

若没有找到,结束返回证书无效;否则,跳到步骤 4)。

判断该证书的 Issuer 值是否等于 Subject 值。

若是,则该证书是根证书,结束返回该证书;否则跳到步骤 6)。

以该证书开始,跳转 2)(继续搜索)。

更多关于信任链的知识点,推荐阅读《What is the SSL Certificate Chain?》

3.4 证书怎么样?
相信不少同学或多或少接触过证书文件,比如.pem、.crt、.cer、.key 等,于是问题就来了:

“为什么有这么多不同后缀名的证书啊?他们有什么联系和区别?”

回答这个问题要从 3 个层面来分析:

证书标准

证书编码格式

文件扩展名

证书标准

数字证书的格式普遍采用的是 X.509 国际标准,维基百科对于 X.509 解释如下:

X.509 是密码学里公钥证书的格式标准。X.509 证书已应用在包括 TLS/SSL 在内的众多网络协议里,同时它也用在很多非在线应用场景里,比如电子签名服务。X.509 证书里含有公钥、身份信息(比如网络主机名,组织的名称或个体名称等)和签名信息(可以是证书签发机构 CA 的签名,也可以是自签名)。对于一份经由可信的证书签发机构签名或者可以通过其它方式验证的证书,证书的拥有者就可以用证书及相应的私钥来创建安全的通信,对文档进行数字签名。

X.509 是 ITU-T 标准化部门基于他们之前的 ASN.1 定义的一套证书标准。
证书的编码格式

X.509 标准的证书文件具有不同的编码格式:PEM 和 DER。

PEM

PEM,全称 Privacy Enhanced Mail,以文本格式存储,以 -----BEGIN
XXX-----开头、-----END XXX-----结尾,中间内容是 BASE64 编码数据。其文本内容大概如下:

html -----BEGIN CERTIFICATE----- Base64编码过的证书数据 -----END CERTIFICATE-----

通常,PEM 格式可以存储公钥、私钥、证书签名请求等数据。查看 PEM 格式证书的信息一般采用如下命令:

openssl x509 -in xxx.pem -text -noout
Apache 和 Nginx 服务器偏向于使用这种编码格式.

DER

DER,全称 Distinguished Encoding Rules,以二进制存储,因此文件结构无法直接预览,只能通过如下命令查看:

html openssl x509 -in xxx.der -inform der -text -noout

DER 格式也可以存储公钥、私钥、证书签名请求等数据。Java 和 Windows 应用偏向于使用这种编码格式。

当然同一 X.509 证书的不同编码之间可以互相转换:

PEM 转为 DER:

openssl x509 -in xxx.pem -outform der -out xxx.der
DER 转为 PEM:

openssl x509 -in xxx.der -inform der -outform pem -out xxx.pem
文件扩展名

不同的扩展名可以分为以下几类:

证书:存放数字证书,X.509 标准,格式可能是 PEM 或 DER。.crt、.cer

密钥:用来存放一个 RSA 公钥或私钥,这类文件不是 X.509 标准,但是是 PEM 或 DER 格式。后缀名有.key。

证书+密钥:可同时存放证书和 RSA 公钥/.pem、.der、.p12

证书请求:并不是证书,而是证书签名请求。csr

IV. 完整性校验:HTTPS 的哈希
哈希,键值对数据结构,通过哈希函数把一个空间映射到另一个空间。非常好用的一个工具,而且哪哪儿都有它的影子,比如负载均衡的一致性哈希、密码学中用于信息加密或数据校验的各种哈希(SHA、MD5 等)、二维空间定位的 GeoHash、对象相似度的 SimHash 等等。

HTTPS 的的哈希一共用在 2 个地方:

4.1 证书的数字签名
具体做法在上文证书一章节已经说过,不再赘述。在这里使用哈希的目的主要是为了减少非对称加密算法 RSA 在长文本上的开销。

对称加密的 Message Digest
在数据通信阶段,SSL/TLS 会对原始消息(message)做一次哈希,得到该消息 message 的摘要,称为消息摘要(Message Digest)。对端接受到消息后,使用协商出来的对称加密密钥解密数据包,得到原始消息 message;接着也做一次相同的哈希算法得到摘要,对比发送过来的消息摘要和计算出的消息摘要是否一致,可以判断通信数据是否被篡改。
4 HTTPS 流程,即客户端和服务端HTTPS通信全过程
在这里插入图片描述
5 实际问题,记录了笔者在实战中遇到的HTTPS相关问题
在加密一章节介绍的 ECDH 是停留在原理层面,实际中密钥协商除了 PreMaster-Secret(即 Client/Server Key)之外,还有客户端和服务端随机数参与,参考文章《Https:TLS 握手协议》,引用文中的图来自展示实际 ECDH 秘钥协商的做法:
在这里插入图片描述\5.2 Change Cipher Spec

Change Cipher Spec是通知对方需要加密参数。文章《TLSde 改变密码标准协议(Change Cipher Spec Protocol)》指出:

SSL 修改密文协议的设计目的是为了保障 SSL 传输过程的安全性,因为 SSL 协议要求客户端或服务器端每隔一段时间必须改变其加解密参数。当某一方要改变其加解密参数时,就发送一个简单的消息通知对方下一个要传送的数据将采用新的加解密参数,也就是要求对方改变原来的安全参数。
SSL 修改密文协议是使用 SSL 记录协议服务的 SSL 高层协议的 3 个特定协议之一,也是其中最简单的一个。协议由单个消息组成,该消息只包含一个值为 1 的单个字节。该消息的唯一作用就是使未决状态复制为当前状态,更新用于当前连接的密码组。为了保障 SSL 传输过程的安全性,双方应该每隔一段时间改变加密规范。

5.3 Encrypted Handshake Message

Encrypted Handshake Message作用就是确认协商出来的对称加密密钥 SK 的正确性,在客户端和服务端协商得到对称加密密钥 SK 之后,互相给对方发了一条用 SK 加密的消息,如果这个加密的消息被解密校验成功,那么就说明对称加密密钥 SK 是正确的。

5.4 单向验证和双向验证

本章全部所探讨的案例都是基于单向验证,即客户端向服务端请求证书、验证服务端身份。在一些实际场景中,对安全性的要求更高,有服务端要求验证客户端的身份,即双向验证。双向验证在单向验证基础上,增加“在服务端发送证书之后,向客户端发送‘请求证书’请求,接着验证客户端身份”这个步骤。参考下图(图片出处不查):
在这里插入图片描述

VI. HTTPS 实战问题记录
问题:HTTPS 是否需要做域名劫持?

没必要。

原因如下:https 在证书校验这步,客户端除了通过对比数字签名来校验证书的有效性,还会比较证书上的域名是否与自己要访问的域名一致。因此,只要服务器的证书是可信的且客户端不跳过“证书验证”这个步骤,https 能够防止域名劫持。

笔者在实际中做过防止域名劫持的工作,具体做法是:首先,客户端向可信赖的域名服务器请求域名对应的 IP 地址;接着,客户端用 IP 替换域名进行网络请求。被称为HTTPS 的 IP 直连。但在实际中会遇到了一个问题:域名身份不对。根本解决方案是:1).书校验时,选择自己定义的 hostname 进行校验;2).证书校验前,把 URL 的 IP 替换回域名。在很多语言实现中,解决方案更为简单:在请求头部的增加 host-name 字段,值填入域名即可。

问题:“x509: certificate signed by unknown authority”

这个问题是客户端拿到了服务器的证书要进行身份验证,但是通过证书信任链策略发现中间断了,搜索不到根证书。说白了就是客户端本地没有签发这个用户证书的根证书或中介证书。

实际中的解决办法有:1). 缺啥装啥,没有根证书/中介证书,那就安装上;2).跳过证书身份验证这步。GoLang 中跳过身份验证的实现:

client := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
}

问题:https 项目中,服务端怎么管理证书和 RSA 密钥?

看情况。

如果是正规的公司,一般会有统一的接入层帮忙做掉,后台开发程序员只需要关心自己的业务逻辑即可。运维同事或者是负责接入层开发的同事们会定期更新证书,负责帮忙做 HTTPS 的 RSA 管理。而且这些证书都是由正规权威 CA 机构签发的,普遍的客户端设备上都预置了对应的根证书。
如果是个人,一般没有条件负担 HTTPS 证书费用,因此可以选择自己签发自签证书,或者到免费的证书签发机构申请证书。但是这类证书要求在客户端上同步安装对应的根证书。

问题:https 项目中,客户端的根证书要提前安装吗?
上一个问题中已经提到了:

如果是正规权威 CA 机构签发的证书,一般不需要提前安装;
如果是私人签发的证书,需要提前安装。
但是,笔者在边缘计算设备上开发时发现,比如摄像头这类的“tinny os”上,是一个“阉割”版本的 Linux 系统,因此没有安装任何根证书。在这类设备上做 https 通信,一定需要提前安装根证书才行。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值