- Published on
让我们懂点儿HTTPS
通俗点来说,HTTPS就是HTTPS + SSL,即在SSL层(传输安全层)传输HTTP信息。和HTTP不同的是,HTTPS协议是在443端口而不是80端口上传输的。它传输加密的数据,比传输明文的HTTP更安全。
非对称加密算法
SSL协议的核心是非对称加密算法。在非对称加密算法中,存在公钥和私钥。由公钥加密的内容,只能由私钥解密,反过来也是如此。但是非对称加密算法对 加密数据的长度有限制 ,而且加解密对机器的压力比较大。
简化的HTTPS请求过程
- 客户端发送一个HTTPS请求,如https://www.xxx.com/query
- 服务端返回由服务端公钥,签发机构CA的信息, 服务端的附加信息,以及由 CA私钥加密的签名数据 (签名一般是数据的hash值)组成的证书。证书的作用就是用来服务器的信息,类似于身份证。
- 客户端使用预置的 CA 列表检查证书的有效性,即是否属于请求的域名,签发机构是否信任等,同时客户端使用相同的算法生成签名,和由CA公钥解密出来的签名数据比较,如果不一致,说明证书被篡改过,浏览器会提示用户该连接不安全。
- 客户端生成一个随机的对称密钥,使用证书中包含的服务端公钥加密之后传给服务端。
- 服务端使用私钥解密拿到这个随机的对称密钥。
- 之后的通信都使用 对称加密算法 进行通信。(因为使用非对称加密算法加密所有的数据对机器的压力太大,所以后续的通信都是用性能比较好的对称加密算法加密数据。)

关于CA证书
从HTTPS的请求过程中,我们可以看到,CA证书在其中起到了至关重要的作用。证书的作用之一就是分发服务器的公钥。
证书一般由 权威的公认的结构签发 。 我们申请一个证书的时候,一般需要提供我们服务器的公钥 。然后CA机构将我们提供的公钥以及其他一些信息,使用CA的公钥进行加密,并且生成一个签名数据(hash)。然后将这些信息放到一个文件里,就生成了一个由当前CA机构签发的证书了。
CA证书是有信用等级的,高层的证书可以给底层的证书做信用背书的。根证书一般都是内置在浏览器或者系统中,相当于自动信任他们。
在chrome --> 隐私设置和安全性 --> 证书管理中,我们可以看下浏览器信任的根证书都有哪些。

为什么SSL证书需要收费
SSL证书通常来说都是收费的,并且价格还不菲。

那么为什么SSL证书需要收费,而且还这么贵呢?
对于CA厂商来说,显而易见的成本有律师法务审计会用,证书签发系统的研发费用,CRL、OCSP等服务的日常运维费用等,所以维护SSL证书也是有很大成本 的,它不是简单拷贝一个电子文件那么简单。
SSL证书的类型 也有区分,高级别的证书在签发的时候,不仅会验证域名所有权,还会人工审核企业的主体信息。在浏览器中,高级别的证书会显示绿色的地址栏,对于企业来说,这很好的彰显了其品牌力。
使用openssl 生成自签名证书
下面的示例将演示如何在Linux(windows下也可以使用WSL)上使用openssl生成一个自签名的SSL证书。
- 创建conf 配置文件
[ req ]
default_bits = 2048
default_keyfile = server-key.pem
distinguished_name = subject
req_extensions = req_ext
x509_extensions = x509_ext
string_mask = utf8only
[ subject ]
countryName = Country Name (2 letter code)
countryName_default = US
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = NY
localityName = Locality Name (eg, city)
localityName_default = New York
organizationName = Organization Name (eg, company)
organizationName_default = Example, LLC
commonName = Common Name (e.g. server FQDN or YOUR name)
commonName_default = Example Company
emailAddress = Email Address
emailAddress_default = test@example.com
[ x509_ext ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
subjectAltName = @alternate_names
nsComment = "OpenSSL Generated Certificate"
[ req_ext ]
subjectKeyIdentifier = hash
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
subjectAltName = @alternate_names
nsComment = "OpenSSL Generated Certificate"
[ alternate_names ]
DNS.1 = example.com
- 生成服务器私钥和证书请求文件。
openssl req -config example.conf -new -sha256 -newkey rsa:2048 \
-nodes -keyout example.com.key -x509 -days 365 \
-out example.com.crt
使用node部署一个HTTPS站点
接下来我们使用node,用上面生成的私钥和证书文件来部署一个HTTPS站点。
- 启动node站点
//根据项目的路径导入生成的证书文件
var privateKey = fs.readFileSync(path.join(__dirname, './spaas.key'), 'utf8')
var certificate = fs.readFileSync(path.join(__dirname, './spaas.crt'), 'utf8')
var credentials = { key: privateKey, cert: certificate }
//创建HTTPS服务器
var httpsServer = https.createServer(credentials, function (req, res) {
res.status(200).send('hello https').end()
})
httpsServer.listen(8001)
此时如果访问https://localhost:8001,浏览器会提示privacy error。

出现ERR_COMMON_NAME_INVALID这个错误,是因为我们服务器使用的证书是颁发给example.com的(上面的conf文件中最后一句), 和当前的域名localhost不匹配。
修改系统HOST文件,将example.com 指向127.0.0.1
127.0.0.1 example.com
此时再次访问https://example.com:8001, 浏览器依然提示privacy error。

但是另外的错误ERR_CERT_AUTHORITY_INVALID 。 出现这个错误的原因是因为这个证书是我们自己签发的,它并不被浏览器和系统信任。接下来我们将它安装到系统的
受信任的根证书颁发机构在控制台中打开security, 然后选择View certificate, 将证书文件导出,之后双击安装。


安装成功后,重新请求https://example.com:8001, (可能需要重新启动浏览器),就显示我们的连接是安全的了。
弄一个私人的证书签发机构
之前我们说过证书也是有层级的,高层的证书可以给低层的证书做信用背书。也就是说,如果系统已经信任了一个我们自签的证书,那么由这个证书颁发的子证书都会被信任。
申请免费的SSL证书
https://certbot.eff.org/lets-encrypt/ubuntubionic-other
https://www.jianshu.com/p/4220bdbda0e1