为 WordPress 全站开启强制 HTTPS 访问

其实早在2月份就已经给域名配置了 SSL 证书,但是当时只用于 VPS 后台的访问,后来给 WordPress 后台也添加了强制 HTTPS 访问,今天则终于给全站都开启了强制 HTTPS 访问。

实际上对于开启 HTTPS 访问并不是难事,对于我而言只要在后台管理面板里导入证书就可以了。但是全站强制访问和激活 Chrome 上的小绿锁就需要另外的配置了。

为站点开启 HTTPS 强制跳转

全站强制访问通过修改 .htaccess 文件实现。一般情况下用户访问网站时都不会专程加上 https:// 来使用 HTTPS 协议连接,因而就需要在用户通过 HTTP 连接时强制跳转至 HTTPS 协议下。但是,搜索引擎在抓取网站时可能会因为网站强制使用了 HTTPS 协议而抓取失败(应该是除了 Google 其他引擎都不支持),所以针对搜索引擎的蜘蛛需要将他们重新因导至 HTTP 协议下。

这里还有另外一个问题,引导强制转入 HTTPS 协议后,除了首页之外,其余自定义链接可能会遭遇 404 的情况。而我的网站就是全部采用了自定义链接,所以在刚配置好强制跳转后再点击其他页面就遭遇了全部 404 的问题,而且还是默认页面的 404 而非博客主题定制的 404 页面。因而除了 HTTP 转 HTTPS 外,还要配置与自定义链接相关的跳转。

参考了 wzyboy的博客文章 和 WordPress论坛的一篇帖子 后,照葫芦画瓢的配置如下:

RewriteEngine On
RewriteCond %{REQUEST_METHOD} POST
RewriteCond %{REQUEST_URI} .wp-comments-post/.php*
RewriteCond %{HTTP_REFERER} !.*molun.net.* [OR] RewriteCond %{HTTP_USER_AGENT} ^$
RewriteRule (.*) ^http://molun.net/$ [R=301,L]
RewriteCond %{HTTPS} !on [NC]
RewriteCond %{HTTP_USER_AGENT} !(baiduspider|soso|bing|sogou|yahoo|sohu-search|yodao|robozilla|msnbot|msie|feedburner) [NC]
RewriteRule (.*) https://molun.net%{REQUEST_URI} [R=301,NC,L]
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

*在使用时记得将域名改为自己的网站域名

*2015年11月14日修改:第三行语句中“wp-comments-post”后跟的原是反斜杠,实际应该为斜杠,现在已经修改。

基本上完成上述步骤后,网站就能够实现全站强制 HTTPS 访问了。但是按照 Chrome 的标准的话,此时也只能得到一个灰锁或带三角的灰锁而非完全的绿锁。

这其中可能有两个原因,一个是未使用新型加密套件,另一个是网站加载了不安全的脚本。前者是服务器的问题,后者是主题的问题。

提升服务器 SSL 安全性(以 Nginx 为例)

一般而言服务器的 SSL 模块默认并不会采用新型的加密套件,需要进行手动指定。如果是使用 Nginx 的用户,可以通过修改 nginx.conf 文件来指定采用新型的加密套件,从而增强 HTTPS 通信的安全性。

根据 pupboss 的文章和 SSL Labs 旗下 排除弱 DH 素数组的相关文章 的建议,建议在 nginx.conf 添加的内容如下:

ssl_session_cache shared:SSL:10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on; ssl_ciphers "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA";
ssl_dhparam /your/path/to/dhparam.pem;
add_header Strict-Transport-Security max-age=15768000;
ssl_stapling on; ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 10s;
ssl_trusted_certificate /your/path/to/domain-trust-chian.pem;

第一部分应该是默认配置。

第二部分是指定采用 TLS 通讯协议,而不采用不安全的 SSL2 或 SSL3,你也可以写成 SSLProtocol all -SSLv2 -SSLv3 这样的形式来启用所有支持的协议但排除 SSLv2 和 SSLv3 。

第三部分,启用加密模组替换,当前列的加密模组不受支持时,再采用后面的模组。末尾以叹号开头的则代表不使用的不安全加密模组。

第四部分,不使用 OpenSSL 提供的默认 1024 位 DH 素数,而是使用自己运算出的 DH 素数组。运算 DH 素数可以通过 <span class="hljs-tag">openssl</span> <span class="hljs-tag">dhparam</span> <span class="hljs-tag">-out</span> <span class="hljs-tag">dhparam.</span><span class="hljs-class">pem</span> 4096 命令来生成,该命令将会在目录下生成 <span class="hljs-tag">dhparam.</span><span class="hljs-class">pem 文件,之后将文件路径填入此参数中。有关为何要这么做可以阅读  WeakDH 上的页面。规避这一问题还可以通过采用 ECDHE 传输形式来实现,对此的建议是采用 ECC 算法签发证书,可以参阅《为网站签发 ECC SSL 证书》。但是由于 ECDHE 算法在移动设备上不一定能够得到良好支持,所以还是需要为移动设备访问做出这一选项的预备。

第五部分,部署 HSTS 安全传输,要求网站直接发送 HTTPS 请求。

第六部分,OSCP 装订,用以在访问时主动验证提供的 SSL 证书状态,是否吊销或者符合在线证书列表提供的记录。由于每次主动请求 OSCP 信息可能会遭到攻击者的拦截,可以通过发送 OSCP 的缓存请求,绕开每次都需要向 OSCP 服务器发送请求的步骤。如果在配置 SSL 证书时并未提供对应的根证书与中级证书,需要自行生成一套证书链,并通过 ssl_trusted_certificate 参数来指定可信赖的证书链。所谓的证书链文件,是指在一个文件中包含了从根证书到为你的网站证书签署的中级证书的全部文本,即复数的 -----BEGIN CERTIFICATE----------END CERTIFICATE-----。本站提供的证书链是 UserTrust 网络的三份证书,分别是 AddTrust External CA RootCOMODO ECC Certification Authority还有COMODO ECC Domain Validation Secure Server CA。证书商在向你派发证书文件时,一般都会以 .ca.ca-bundle 文件的形式为你提供证书链文件。

一般而言通过以上步骤就可以提高服务器的通讯安全性,在 SSL Test 中也能拿到好成绩。2015年11月14日本站的测试结果如下:

SSLTest

重加载网站的不安全脚本

网站主题本身的不安全脚本主要是在访问网站时,诸如 CSS、JS 这些内容并没有强制通过 HTTPS 传输,而是通过 HTTP 来传输的,即以混合内容的形式呈现网站。要想使网站的安全性能够进一步提升,则需要将这些脚本内容也通过 HTTPS 进行传输。

最开始我是通过修改主题文件的形式来试图实现的,但是发现 CSS 在被指定为 HTTPS 协议传输后就不顶用了,博客页面被毁得一团糟,在暂时没办法排查清楚的情况下,我选择通过插件来解决这个问题。

目前网站使用的是 SSL Insecure Content Fixer 插件(目前已由我汉化完毕),它能够重载网页上不安全的内容并通过 HTTPS 协议的形式向用户发送,从而使整个网页的一切内容都能处于安全传输的环境下。根据需要的不同,可以选择不同的重载范围,避免占用过多的服务器资源。不过我的 VPS 上网站少资源也比较充裕,而且 CSS 和 JS 脚本也需要进行安全传输,所以选择的是需要资源最多的最高等级来协助网站向 HTTPS 转换。

 

通过以上措施,就可以在为全站开启 HTTPS 访问的同时提升安全性及安全体验了。

目前整个博客已经实现了全站 HTTPS 访问以及 Chrome 的小绿锁认证,不过外链的图片已经挂掉了,还得慢慢将其转移到自己的 VPS 上进行更新,还好图片不是特别多,慢慢来吧。

 

2015年12月16日 更新

题图:《HTTPS Browser》来自原作者 Yuri Samoilov 的 Ficker 页面。采用 CC BY 2.0 协议进行授权。

18 条评论

回复 漠伦 取消回复

  • […] 此后,就可以提交给证书商来为你签发 SSL 证书了。拿到 SSL 证书后,可以在服务端修改自身的 SSL 配置以提高安全体验,包括采用对应的 ECDHE 交换机制和重载网站的不安全内容,有关这些配置,可以参阅《为 WordPress 全站开启强制 HTTPS 访问》。 […]

    • 参阅 这篇文章 里相关 Apache 的部分,由于文章里提及了两种 Apache 环境,我不能够判断应该选择哪个。一般而言都是选择“Apache HTTP Server (mod_ssl)”这一分类下的指南。即修改 httpd.conf 文件里的相关配置。一般而言修改完毕后影响 SSL 安全性最主要的加密套组的问题就能解决了。
      但是那篇文章只提及了增加 DH 数组和修改加密套件的优先级两个方面,博客正文中提及的其他部分没有涉及。由于我没配置过 Apache,虽然记忆里应该是能够通用,但仍不能保证其他部分的配置是否通用于 Nginx 与 Apache,这点也请知悉。
      如果保存文件时,系统没有提示某行有错误,就可以认为配置是有效的。

  • 请问下,我注册了个免费的证书,提供了PEM和KEY

    ssl_dhparam /your/path/to/dhparam.pem;
    ssl_trusted_certificate /your/path/to/domain-trust-chian.pem;

    那个选择KEY文件,那个选择PEM文件呢?

    • dhparam.pem 是自己生成的。

      PEM 和 KEY 应该填在这两行:
      ssl_certificate /root/(你的路径)/fullchain.pem;
      ssl_certificate_key /root/(你的路径)/pupboss.com.key;

      • 删除dhparam.pem这一行没问题吗?
        然后KEY文件就填写在
        {
        resolver 8.8.8.8 8.8.4.4 valid=300s;
        resolver_timeout 10s;
        ssl_trusted_certificate /your/path/to/domain-trust-chian.pem;
        ssl_certificate_key /root/(你的路径)/pupboss.com.key;
        }
        这下面吗?

        • (我这里默认你使用的是 Nginx)
          不对。如果你是为了启用 HTTPS 的话,首先应该把你的证书文件和 Key 文件上传到服务器后,在 Nginx.conf 里填上这两行
          ssl_certificate /root/(你的路径)/fullchain.pem;
          ssl_certificate_key /root/(你的路径)/pupboss.com.key;

          确认这么填写能够成功为网站开启 HTTPS 后,再来跟进这篇文章的其他部分。因为这篇文章不是从零开始配置的。
          如果你使用的是 Nginx 系统,可以额外参考这篇文章,它写得更为详细一些。
          这是我的部分配置参考:
          ssl on;
          ssl_certificate /usr/local/vesta/ssl/certificate.crt;
          ssl_certificate_key /usr/local/vesta/ssl/certificate.key;
          ssl_session_cache shared:SSL:10m;
          ssl_session_timeout 10m;
          ssl_ciphers "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA";
          ssl_prefer_server_ciphers on;
          ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
          ssl_session_tickets on;
          ssl_stapling on;
          ssl_stapling_verify on;
          resolver 8.8.8.8 8.8.4.4 valid=300s;
          resolver_timeout 10s;

  • 同学,请教个问题,我网站换成https后 css 和js 都不加载,看源码 css 和js 都还是http开头的,在网站后台设置 改成https开头,可css js 依然是http开头。请问这种情况怎么修改? 感谢

  • […] 某站点全文 Copy 了我的《为 WordPress 全站开启强制 HTTPS 访问》这篇文章转载到自己的网站。自然,没写出处。还说是自己的“原创”,尽管唯一的原创部分就是用心地把文章里面的 .htaccess 里的域名给改成了自己网站的域名。 […]