# 第八章 HTTPS

# 参考资料

HTTP 最大的变化发生在 1994 年底。HTTP 在基本的 TCP/IP 协议栈上发送信息,网景公司(Netscape Communication)在此基础上创建了一个额外的加密传输层:SSL 。

# HTTP 的缺点

HTTP 主要有这些不足,例举如下

  • 通信使用明文
  • 不验证通信的身份
  • 无法验证报文的完整性

所谓互联网,是由能连通到全世界的网络组成的,所以不排除通信中的某个环节会遭到恶意窥视行为。即使已经经过加密处理的通信,也会被窥视通信内容,只是说通信经过加密后就可能让人无法破解。

窃听相同网段上的通信并非难事,只需要收集在互联网上流动的数据帧就行了,对于收集来的数据包的解析工作可以交给抓包 Packet Capture 或嗅探器工具。被广泛使用的一个抓包工具是 Wireshark。

通信的加密

HTTP 协议中没有加密机制,但可以通过和 SSL(Secure Socket Layer, 安全套接层)或 TLS(Transport Layer Security, 安全层传输协议)的组合使用,加密 HTTP 的通信内容。

内容的加密

还有一种是只对通信的内容本身进行加密,即把 HTTP 报文里所含的内容进行加密处理,有一点必须注意,由于该方式不同于 SSL 或 TLS 将整个通信线路进行加密处理,所以内容仍有被篡改的风险。

查明对手的证书

虽然使用 HTTP 协议无法确定通信方,但是使用 SSL 则可以,因为 SSL 不仅提供加密处理,而且还使用了一种被称为证书的手段,可用于确定通信方。

HTTP 无法证明通信的报文完整性,可能受到中间人攻击。

# HTTP+加密+认证+完整性保护 = HTTPS

HTTPS 并非应用层的一种新协议,只是 HTTP 通信接口部分用 SSL 和 TLS 协议代替而已。通常 HTTP 直接和 TCP 通信。当使用 SSL 时,则演变成先和 SSL 通信,再由 SSL 和 TCP 通信。

公开密钥加密(非对称加密)

大部分的加密算法都是公开的,而密钥确实保密的,通过这种方式来保证加密通信的安全性,但是一旦密钥被攻击者获得,那加密也就失去了意义。

  • 共享密钥(一个密钥)加密的困境

    加密和加密使用同一个密钥的方式称为共享密钥加密,也被称为对称加密

    如果在互联网上转发密钥时,一旦通信被监听那么密钥就可能会落入攻击人之手。

  • 使用两把密钥的公开密钥加密

    其中数据加密的密钥是公开的,而解密的密钥是私有的,也被成为非对称加密

    ϕ(n)\phi(n)是关于 n 的一个函数,表示小于 1-n 之间和 n 互质的数的个数

    对于质数而言有这样两个规律

    ϕ(p)=p1\phi(p)=p-1

    ϕ(pq)=ϕ(p)ϕ(q)\phi(p*q)=\phi(p)*\phi(q)

    使用公开密钥加密方式,发送密文的一方使用对方公开的密钥进行加密,对方接收到被加密的信息后,再使用自己的私有密钥进行解密。利用这种方式,不需要发送用来解密的私有密钥,也不必担心密钥被攻击者窃听而盗走。

  • HTTPS 采用共享密钥加密和公开密钥加密两者并用的混合加密机制

  • 遗憾的是公开密钥加密也存在一些问题,那就是无法证明公开密钥本身就是货真价实的公开密钥。目前对这个问题的一个解决方案是使用由数字证书认证机构和其相关机构颁发的公开密钥证书

SSL 和 TLS

HTTPS 使用 SSL 和 TLS 这两个协议,SSL 技术一开始由网景公司倡导开发,但是 SSL3.0 之前的版本存在问题,IETF 以 SSL3.0 为基准,后来又制定了 TSL1.0、TSL1.1 和 TSL1.2。TLS 是以 SSL 为原型开发的协议,当前的主流版本是 SSL3.0 和 TLS1.0。

SSL 慢吗?

SSL 的慢分两种,一种是指通信慢,除去和 TCP 连接,发送 HTTP 响应/请求之外,还要和 SSL 通信,因此整体上处理的通信量不可避免的增加。另一点是 SSL 必须进行加密处理,会大量消耗 CPU 及内存等资源。

# HTTPS 信任机制

# RSA

# Open SSL

使用 Open SSL 生成私有 SSL 证书

[req]
default_bits  = 2048
distinguished_name = req_distinguished_name
req_extensions = req_ext
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
countryName = CN
stateOrProvinceName = HN
localityName = CS
organizationName = Self-Cert
commonName = Self-Cert
[req_ext]
subjectAltName = @alt_names
[v3_req]
subjectAltName = @alt_names
[alt_names]
IP.1 = 127.0.0.1

首先,虚构一个 CA 认证机构出来

# 生成CA认证机构的证书密钥key
openssl genrsa -out ca.key 2048
# 用私钥ca.key生成CA认证机构的证书ca.crt
# 其实就是相当于用私钥生成公钥,再把公钥包装成证书
# 这个证书ca.crt有的又称为"根证书",因为可以用来认证其他证书
openssl req -new -key ca.key -out ca.csr --config san.cnf
openssl x509 -req -in ca.csr -CAkey ca.key -signkey ca.key -out ca.crt -days 365

其次,才是生成网站的证书

# 生成自己网站的密钥server.key
openssl genrsa -out server.key 2048
# 生成自己网站证书的请求文件
# 如果找外面的CA机构认证,也是发个请求文件给他们
# 这个私钥就包含在请求文件中了,认证机构要用它来生成网站的公钥,然后包装成一个证书
openssl req -new -key server.key -out server.csr  --config san.cnf
# 使用虚拟的CA认证机构的证书ca.crt,来对自己网站的证书请求文件server.csr进行处理,生成签名后的证书server.crt
# 注意设置序列号和有效期(一般都设1年)
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -signkey server.key -CAcreateserial  -out server.crt -days 365