给你的博客上一把锁

本文主要讲解给自己的博客或站点配置https的必要性和配置方法。

再不https都老了

说到https,可能有一个问题是大家必问的,那就是为啥要用https,我这里能给到的答案就是: 美啊。 先来一张图观赏下:

其实最重要的还是安全,在这个根本没有隐私的时代,https显得更加那么的重要。在你网站被运营商 乱插 的时候,你就会更加迫切的想要一把锁。上锁之前,我们需要对https有一定的了解,下面我们简要学习下。

六问 HTTPS

https握手会使得网站变慢?

大家最关心的就是这个协议会让我们的连接变慢,这个看起来似乎是不可避免的;毕竟建立SSL连接的过程比http多了好几次握手。所以一个https请求的过程中,握手阶段包含了 TCP协议的握手SSL协议的握手 的时间,总体上我通过工具测试大概SSL握手是TCP握手的三倍,而且证书的秘钥越长加解密时间则越多。

然而事实就这么简单吗? 非也

作为中国人,一定对GFW毕竟熟悉了,实际上根据我多年来实际的经历来看,除了GFW,其实不管是在国内的公司还是学校(甚至运营商),实际上都有监控或劫持本组织内网络流量的嫌疑。当网站使用了https,实际上这些监控系统成为摆设,既然无法拆解你的信息,他唯一的做法自然是放过,这就大大加速了数据在网络中的传输速度。所以:

使用了https表面上看起来是在连接建立阶段增加了时间,然而实际上对网站整体的速度来说,未必真的慢了。

只需要在注册登录页面使用https?

这只能防止密码劫持,并不能防止cookie劫持和js注入等问题;这年头想劫持一个局域网络的简直易如反掌(何况还有天朝的无耻运营商可以随意注入呢),所以如今要想安全,必须全站https

静态资源是否需要https?

如果主要页面已经https了,则你的CDN静态资源也得走https,否则浏览器会给出简单的控制台警告:

不过cdn服务器遍布全球,要想把证书安装到上面可是很费劲的。所以如果想用自己的域名来实现静态资源https化,只能有这两条路:

  1. 要么自己部署cdn自己搞
  2. 要么把证书和秘钥交给自己的cdn服务商。

但是第二个办法实在是太危险了。所以CDN服务商推出了新的服务: 除了允许你上传自己的证书和私钥之外,也可以申请CA证书的服务。这意味着 你可以专门为使用CDN资源的这个域名申请个单独的证书,这个证书是部署到CDN服务商所有服务器的(这样就不用担心自己主业务的服务器私钥泄露给第三方)。目前国内的七牛已经提供了该服务,所以我的博客图片也顺便开启了https。

https没有缓存机制吗?

是的。不过要明确这里的缓存指的是中间网络设施的缓存,而不是客户端缓存。中间网络设施无法缓存的原因在于他们根本无法获取https报文,无法读取缓存策略。

从https的意义上来看 既然想保护信息的隐私,确实也没必要让中间设施进行缓存了。

https是否足够安全?

SSL/TLS的设计只能说是从技术上最大限度地保护网络报文的安全,但它无法防止用户自己作死;比如浏览器已经提示你证书错误的情况下你依然点击”继续访问”。

验证HTTPS证书带来的性能开销是否很大?

实际上整个证书验证的过程中,还可能因为一些其他原因导致耗时增加:

  1. 服务端发送的Server Certificate包可能包含上级证书链,在普遍使用2048位RSA的环境中,这个包会超过2K或者3K,在移动或慢速网络下可能会丢包并引起TCP的重传
  2. 浏览器会检查服务端证书的吊销状态—-根据服务端证书扩展项中的地址去下载黑名单或访问OCSP服务,如果这些地址无法访问或者被墙,则会让浏览器等上很长一段时间。 这可就蛋疼了,毕竟我们处在大中国,而浏览器都是舶来品
  3. 建立连接时的非对称加密算法本身非常耗时,这对CPU性能要求比较高。所以每次握手,对服务器来说都是一次压力的考验

怎么办呢? 我认为是没有办法的,为了安全我们必须做出这样的牺牲;当然这可以从http协议本身来减轻这个性能和速度开销的负担,比如http2.0就已经支持了多路复用的技术,目前的http1.1也支持keep-alive,这就大大减轻了多次创建连接和握手带来的开销。

福利:免费申请https证书

Let’s Encrypt 提供了免费的https证书,目前2018年初已经开始支持 泛域名。 因此对于有多个子域的网站来说,只需要申请根域的证书,就可以应用在所有的子域上面。

申请脚本

网络上已经有写好的申请脚本,使用此脚本申请证书非常方便, 步骤如下:

1
2
3
4
curl https://get.acme.sh | sh
export DP_Id="1234" // 需要去dnspod等域名提供商申请API Key 和 ID
export DP_Key="sADDsdasdgdsf" // API Key 和 ID
acme.sh --issue --dns dns_dp -d limefe.com -d *.limefe.com // 申请免费泛域名证书

以上命令,如果碰上curl错误,可以尝试退出当前terminal再次进入。 由于CA机构需要校验你对域名的所有权,所有你需要把你域名操作的 API_idAPI_key 告诉 Let's Encrypt.

过期重申

Let's Encrypt申请的证书只有3个月有效期,到期需要重新申请。所幸网络上的这个 acme脚本已经实现了自动检查并重新申请的能力,我们就不用关心了。

nginx配置https

nginx配置https其实很简单,只需要按照如下格式,将里面的证书地址和秘钥地址配置成你自己的即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
server {
listen 443;
server_name www.cuiyongjian.com;
ssl on;
# 下面的证书替换成自己的路径
ssl_certificate /root/.acme.sh/cuiyongjian.com/fullchain.cer;
# 下面的key替换成自己的路径
ssl_certificate_key /root/.acme.sh/cuiyongjian.com/cuiyongjian.com.key;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
keepalive_timeout 70;
#add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";
#charset koi8-r;
#access_log /var/log/nginx/log/host.access.log main;
access_log /root/weblogs/nginxlog/www.cuiyongjian.com.https.access.log main;
error_log /root/weblogs/nginxlog/www.cuiyongjian.com.https.error.log;
location / {
root /root/www/www.cuiyongjian.com;
index index.html index.htm;
}
}

在使用 acme.sh 脚本时,证书和秘钥key都会生成到
~/.acme.sh/yourdomain
目录下。
例如我的 cuiyongjian.com 域名证书就被生成到了
/root/.acme.sh/cuiyongjian.com/fullchain.cer;
目录下。

如果你的站点希望强制走https,那么你可以再加一个nginx的server配置项,让http请求重定向到https:

1
2
3
4
5
server {
listen 80;
server_name www.cuiyongjian.com;
return 301 https://$server_name$request_uri;
}

浏览器端查看证书

点击chrome地址栏左侧的小锁图标,可以看到当前网站的证书信息