本博客正式支持HTTPS/SSL浏览(powered by Let's Encrypt)

今天起,本博客已经正式启用https/ssl,页面上链接已经更新为https链接。

使用的是Let's Encrypt提供的免费ssl证书服务。

Let's Encrypt服务优势

免费、支持多域名、国际化,并且服务商是Linux基金会成员,可信度高。

目前主流浏览器都支持该证书的,参看官方的“证书兼容列表”

负面影响评估

以GA上最近1万(准确数字是10523)次会话作样本做评估,GA只计算“人”的访问,而不计蜘蛛,这更符合现实。(可以认定,主流的搜索引擎蜘蛛应该是支持该证书的,这个影响按理可以忽略。)

按网友的经验IE6是不支持的,经过虚拟机下windows 2003里IE6测试证实了这一点(手上没带IE6的xp)。样本会话中共计10次IE6,9次IE7;由此IE6占比不到0.1%即使带上IE7,也不到0.2%. 因此旧版IE可以忽略。

Safari 4.0以下无访问。

 

Let’s Encrypt HTTPS证书申请部署与自动续期/免费ssl,nginx,centos

一年半以前曾经买过一个廉价的https/ssl证书,部署在本博客blog.path8.net上,时间大概在 2015-5-17,然而并没有正式启用,以至于过期也都没有注意。前几天想于把这个事情搞起来。以前的经验是,廉价ssl证书都是只对一个域名有效,但竟然发现Let's Encrypt的免费证书,还是多域名的。近一年的新文章里,有不少人对之大加赞扬;于是准备试试。同时也发现了腾讯云也有免费ssl证书,单域名的,免费一年,试用了一下,签发速度比较快,部署到本站上。不过还是决定使用Let's Encrypt。下面是简单记录。

vps环境CentOS 6.x, niginx

花了半天时间研究Let's Encrypt的相关文章(基本都是中文博客),另外尤其仔细读了其官方网站,开始实际操作,发现真的很简单。

ssh登录到服务器上操作,并且操作需要需要root权限。

1. 自动部署脚本需要epel源,如果之前没有安装先安装之 yum install epel-release

2. 在线获取签署脚本(按自己的习惯保存到合适目录)。签署脚本官方称之为客户端,有多个版本,这里使用的官方推荐的 certbot

wget https://dl.eff.org/certbot-auto
chmod a+x certbot-auto

3. 运行签署脚本。脚本里注意两人参数 -w, -d,分别是一个web目录及该目录对应的域名;多组目录就多次指定。这里只是获得证书文件,不做自动部署。(猜测是因为该脚本不支持nginx的自动部署,毕竟nginx不在centos官方源里,不同服务器上安装方式 不一样)。如下所示。

./certbot-auto certonly --webroot \
-w /var/www/html/blog.path8.net/html -d blog.path8.net \
-w /var/www/html/www.path8.net/html -d www.path8.net -d path8.net -d fengyqf.com

4. 接下来会自动通过yum安装几个依赖包,同意即可。

5. 然后是几步交互式对话:邮箱地址、同意条款、照着操作即可。因为Let's Encrypt是自动签署,速度非常快,大概整个过程只花费了两三分钟(包括交互过程里等待用户操作的时间)。

letsencrypt_req_email

交互询问邮箱地址

按其他网友的文章所说,使用国内dns服务很容易引发域名解析失败;此次使用dnspod却是一次成功的。成功后消息如文后。

在目录里 /etc/letsencrypt/live/{your.domain.ext}/ 得到四个文件:cert.pem chain.pem fullchain.pem privkey.pem  。简单理解,前两个是给Apache用的,后两个是给Nginx用的。(注意 privkey.pem 这个文件是私钥,内容千万要保密!)

事实上这四个文件是到/etc/letsencrypt/archive/{your.domain.ext}/ 下文件的符号链接。从结构上看,更新证书时,会自动更新符号链接目标。

按脚本执行的输出,运行日志记录在 Saving debug log to /var/log/letsencrypt/letsencrypt.log

下面是签署脚本成功执行后的消息。

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/blog.path8.net/fullchain.pem. Your cert will
   expire on 2017-01-14. To obtain a new or tweaked version of this
   certificate in the future, simply run certbot-auto again. To
   non-interactively renew *all* of your certificates, run
   "certbot-auto renew"
 - If you lose your account credentials, you can recover through
   e-mails sent to f***@gmail.com.
 - Your account credentials have been saved in your Certbot
   configuration directory at /etc/letsencrypt. You should make a
   secure backup of this folder now. This configuration directory will
   also contain certificates and private keys obtained by Certbot so
   making regular backups of this folder is ideal.
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

6. 部署证书文件到nginx上。主要是ssl_* 的行,指定为证书目录。

    server {
        listen 80;
        listen 443;
        ssl on;
        ssl_certificate  /etc/nginx/ssl/blog.path8.net_cert.crt;
        ssl_certificate_key  /etc/nginx/ssl/blog.path8.net.key;
        ssl_session_timeout 5m;
        ssl_protocols TLSv1;
        ssl_ciphers HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers on;

        location / {
                index  index.html index.htm index.php;
                # from nginx.org rewrite rule
                # This is cool because no php is touched for static
                try_files $uri $uri/ /index.php;
        }
    ......
    }

7. 重新加载nginx配置,或者重启 nginx -s reload  ,然后测试https访问。记得iptables放行443端口。

8. 如果需要,将80端口301重定向到443.

9. 配置定时任务以自动更新证书。重新签署证书及加载证书,将脚本加入到定时任务中,/path/to/certbot-auto renew --quiet  . 重新加载nginx配置以应用新证书的脚本如  nginx -s reload

凭空想象的应用中的数据加密方案

限制单用户单位时间内最大请求频次

(如每日最多请求50次内容页){仅稍微增加了采集难度,延缓被脱库时间}

对于请求频率异常的设备,封禁若干长时间(如10分钟)

技术方案参考:

  • App在请求接口时,带上设备惟一编号、当前版本号
  • 请求异常时,将设备惟一编号列入黑名单。
  • 设备惟一编号。可以使用友盟统计的 Device Token。<Tips:惟一编号方案不要与苹果的隐私规范冲突>(注意:Android可以通过清空应用数据重置该惟一编号,iOS可通过卸载后重装重置该编号)

加密数据输,请求及响应双向加密。

至少要包括:接口名,参数名,参数值。可以考虑如下加密方案:

  • 使用AES加密算法,AES密文是二进制的,最好再做一次BASE64编码。
  • 通过接口分发密钥,密钥本身也是加密传递,真实密钥需要是经过事先约定的算法计算得到。
  • 不要通过单独的接口分发密钥,而是放在其他接口中,可以放在最低允许的版本号的接口中。响应数据中,增加适量无意义的干扰信息,增加猜解难度。
  • 密钥定期修改,在服务器端更改,App启动时加密分发给App。
  • 在做协议分析时很容易猜解接口名,因此接口名可以采用另外的密钥加密,与数据传输密钥不同。可以是硬编码到App内部的固定密钥。
  • 参数名、参数值放在一起加密,即通过GET请求字符串整体加密。
  • 服务器端响应数据,也是加密后base64编码后返回密文。
  • 固定密钥不要直接出现在App的字符串资源中。

一个接口格式参考

也可以将接口地址格式改成这个形式:

host.domain.ext/interface?model=news&action=list&class=123
host.domain.ext/interface?model=news&action=detail&class=9876

将get参数加密传输后格式示例(下面只是简单的base64,没做加密)

host.domain.ext/interface?bW9kZWw9bmV3cyZhY3Rpb249bGlzdCZjbGFzcz0xMjM
host.domain.ext/interface?bW9kZWw9bmV3cyZhY3Rpb249ZGV0YWlsJmNsYXNzPTk4NzY

甚至把interface一段也重写隐藏掉,形式如

host.domain.ext/bW9kZWw9bm3cyZhY3Rpb249bGlzdCZjbGFzcz0xMjM

对于POST请求,将post包与做类似的加密封装

其它杂项

一个接口:最低允许的版本号。作用:App启动时,检查版本号,如果App版本号过低,强制用户更新。(类似网络游戏启动时检查版本补丁的方式)

如果有在线接口文档,其地址(目录命名、目录层级等)要有一定复杂度,避免被猜到。最好是授权查阅(口令、账号、IP段等)