让网站支持Https

HTTPS 原理

HTTPS 相比 HTTP 而言多了一个 s,也就是 SSL(Secure Sockets Layer),安全套接层。SSL 做的事情就是将用于通信的对称加密密钥进行非对称加密,以此来实现高效且安全的通信。整个 HTTPS 通信的时序图如下,包含了 HTTPS 四次握手。

![Alt text](1e7e149c-7ffd-421b-aa19-302cd053a5d1.png)
  1. 客户端发起一个https的请求,把自身支持的一系列Cipher Suite(密钥算法套件,简称Cipher)发送给服务端
  2. 服务端,接收到客户端所有的Cipher后与自身支持的对比,如果不支持则连接断开,反之则会从中选出一种加密算法和HASH算法
    以证书的形式返回给客户端 证书中还包含了 公钥 颁证机构 网址 失效日期等等。
  3. 客户端收到服务端响应后会做以下几件事
  • 验证证书的合法性
    颁发证书的机构是否合法与是否过期,证书中包含的网站地址是否与正在访问的地址一致等
    证书验证通过后,在浏览器的地址栏会加上一把小锁(因浏览器而异)
  • 生成随机密码
    如果证书验证通过,或者用户接受了不授信的证书,此时浏览器会生成一串随机数,然后用证书中的公钥加密。
  • HASH握手信息
    用最开始约定好的HASH方式,把握手消息取HASH值, 然后用 随机数加密 “握手消息+握手消息HASH值(签名)” 并一起发送给服务端
    在这里之所以要取握手消息的HASH值,主要是把握手消息做一个签名,用于验证握手消息在传输过程中没有被篡改过。
  1. 服务端拿到客户端传来的密文,用自己的私钥来解密握手消息取出随机数密码,再用随机数密码 解密 握手消息与HASH值,并与传过来的HASH值做对比确认是否一致。然后用随机密码加密一段握手消息(握手消息+握手消息的HASH值 )给客户端
  2. 客户端用随机数解密并计算握手消息的HASH,如果与服务端发来的HASH一致,此时握手过程结束,之后所有的通信数据将由之前浏览器生成的随机密码并利用对称加密算法进行加密。因为这串密钥只有客户端和服务端知道,所以即使中间请求被拦截也是没法解密数据的,以此保证了通信的安全

在客户端与服务端相互验证的过程中用的是对称加密,客户端与服务端相互验证通过后,以随机数作为密钥,对称加密 hash 算法也同时确认握手消息没有被篡改。

SSL For Free & Let’s Encrypt

通过上面的描述,可以看到这里我们需要一个由认证机构(CA)颁发的 SSL 证书才能实现 HTTPS 通信,一般而言申请和更新 SSL 证书都是需要一定费用的,但是 SSL For Free 为我们提供了一个免费获得 SSL 证书的渠道
Alt text
在 SSL For Free 上可以获得由开放证书认证机构 Let’s Encrypt 颁发的 SSL 证书,该机构受到很多企业和机构的捐赠以保持免费,这个证书获得世界上绝大多数的浏览器认可,可以说是一个福利。

施工过程

施工的过程相对来说很简单,以我的 Nginx 服务器为例分为以下几个步骤:

  1. www.sslforfree.com 上输入你的域名,然后点击按钮创建 SSL 证书
    Alt text
  2. 然后转圈过后会进入下一个页面
    Alt text
    按照上图的描述,选择手动认证,如果你有部署 FTP 可以选用第一个方式。然后点击最下方的按钮。将页面向下滚动之后会出现以下的内容。
    Alt text
    点击下载认证文件
    Alt text
    然后将下载好的认证文件按照图片中的说明部署到网站的目录中。通过下方提供的绿色链接可以验证部署是否成功。完成之后点击下方的绿色按钮。
    Alt text
  3. 到下一个页面中下载包含证书和密钥的压缩文件到本地,解压,然后将文件上传到服务器的某个位置。
  4. 配置 Nginx
    /etc/nginx/sites-available 中的站点配置文件里加上如下内容
1
2
3
4
5
6
7
 server {
...
listen 443 ssl;
ssl_certificate {证书目录}/certificate.crt;
ssl_certificate_key {证书目录}/private.key;
...
}

然后重启或者 reload Nginx。
5. 如果 443 端口处于关闭状态,则还需要到 iptables 配置中将 443 端口开放。

至此整个施工结束。

强制 HTTPS 访问

在做如上配置之后你会发现网站既可以通过 http 也可以通过 https 访问,如何强制使用 https 访问呢?也很简单,只需要再给 Nginx 站点配置中添加一条新的规则。

1
2
3
4
5
server {
listen 80;
server_name {域名};
return 301 https://{域名}$request_uri;
}

通过 301 跳转的方式将非 https 的访问变更为 https 方式实现了强制 https 访问。