这段时间工作开发的网站用的是https,每天看着地址栏又个绿色的小锁很是开心。打开自己的博客发现毛豆没有很是不爽,查了查发现有免费的 SSL 证书就花了一些时间把博客配置了 https,这里记录一下步骤。
1.申请证书
首先要为域名申请一个 SSL 证书,我用的是 StarSSL 的免费的 DV 证书。注册后网站会给一个登录证书将这个登录证书导入到系统,以后登录的时候会用到。登录进去后按照流程进行域名验证,也就是给邮箱发个邮件,如果没有域名邮箱可以开一个阿里的或者腾讯企业的,实在不行临时关掉域名 whois 信息保护,给自己发一个也是可以的。
域名验证后,点击 Certificates Wizard 选择 Web Server SSL/TLS Certificate 然后点击 Continue ,如下图:
在 Please enter the full hostname for SSL certificate (e.g: mail.domain.com) 中输入域名,这里有个技巧,一般我们会在 www.chenky.com 和 chenky.com 选择一个,另一个做301跳转因此在这里输入这两种域名会方便后续的跳转。
当然主域名要放在第一个,我想的页面跳转逻辑如下图,其中301和307我后面会解释如何实现:
接下来 Please submit your Certificate Signing Request (CSR) 中选择 Generated by Myself (.cer PEM format certificate) ,这里既需要详细说一些如何实现了。我这里用的 OS X 所以以下命令是可以直接执行的。
首先生成 pem 格式的密钥,算法用的是 rsa:
openssl genrsa -out www.chenky.com.pem 2048
然后用这个密钥生成证书的描述文件:
openssl req -new -key www.chenky.com.pem -out www.chenky.com.csr
这一步需要输入一些基本信息由于是DV级别所以这些信息不会在证书中展示,但还是如实填写比较好:
将 www.chenky.com.csr 文件中的内容复制到文本框中,正确的 csr 文件在右侧会给出加密算法和密钥长度:
点击 Submit 后会看到成功界面:
点击 here 会下载一个 zip 压缩包,其中 NginxServer.zip 中就是我这里需要的证书,另外在 OtherServer.zip 中有根证书和中间证书:
这个 crt 文件就是证书了,配合之前的 pem 密钥就可以配置https了。
2.配置 Nginx
首先将上面的 pem 文件和 crt 文件上传到服务器的指定目录,比如使用的目录是:
/etc/nginx/conf.d/CA/www.chenky.com.crt /etc/nginx/conf.d/CA/www.chenky.com.pem;
确保 Nginx 有读取他们的权限,在 Nginx 配置的Server 中修改监听为443
listen 443;
并打开ssl
ssl on; ssl_certificate /etc/nginx/conf.d/CA/www.chenky.com.crt; ssl_certificate_key /etc/nginx/conf.d/CA/www.chenky.com.pem;
为了使 http://www.chenky.com 能够跳转到 https://www.chenky.com 在 Server 后新增 Server :
server { listen 80; server_name www.chenky.com; return 301 https://www.chenky.com$request_uri; }
保存后重启 Nginx 即可:
3. Nginx https 相关配置优化
在开启了https后需要对 Nginx 进行优化,以增加安全性。先给出几个测试网站https安全性的网站:
通过上面几个网站的测试结果可以看出配置中问题。
配置对协议的支持(引用)
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
配置加密方式(引用)
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';
配置 DH parameters 文件(引用)
要明白这个文件的作用首先要理解这个DH是什么。DH是一种密钥交换协议介绍看这里,足够长的DH文件可以保证安全,因此建议使用2048或者4096长度的
生成该文件:
openssl dhparam -out dhparams.pem 2048
增加配置:
ssl_dhparam /etc/nginx/conf.d/CA/dhparams.pem;
配置以服务器加密方法优先(引用)
ssl_prefer_server_ciphers on;
启用CSP(引用)
CSP(Content Security Policy)是一种额外安全措施用来防止 Cross-Site Scripting (XSS)攻击。
CSP有大量的配置项(查看)我们根据自己情况有选择的配置,基本上是对js、css和图片进行限制:
add_header Content-Security-Policy "default-src *; img-src * data:; font-src * data:; script-src 'self' *.chenky.com *.cnzz.com *.google-analytics.com dn-staticfile.qbox.me 'unsafe-inline' 'unsafe-eval'; style-src 'self' *.chenky.com 'unsafe-inline'";
关闭浏览器自动识别文件功能(引用)
add_header X-Content-Type-Options nosniff;
阻止在<frame><iframe><object>中打开其他页面(引用)
add_header X-Frame-Options SAMEORIGIN;
启用IE中XSS防护
add_header X-XSS-Protection "1; mode=block";
启用HSTS(引用)
HSTS(HTTP Strict Transport Security)是一项安全配置,他告诉浏览器应该只用https不用http。
大多数时候我们从地址栏输入地址,或者点击某些早期存储的书签后浏览器会默认的一http协议访问该网站(自动补全除外),对于https站点这并不是一个问题只需要在Nginx中配置80端口的301跳转就行:
通过301虽然可以访问,但是由于第一次是http访问因此可以在第一次访问的时候发起攻击:
通过chrome的开发者工具可以看到,在没有配置HSTS之前,访问时这样的:
如下配置:
add_header Strict-Transport-Security "max-age=31536000; preload";
max-age的作用是是告诉浏览器HSTS要保持多久,再次打开是这样的:
那什么是307呢,307表示 Internal Redirect 也就是内部跳转,意味着浏览器自主的将http改成了https:
这样只要用户正常访问过一次网站,后续就不用担心301跳转的问题了,当然还可以在这里将自己的域名添加到各个浏览器的 HSTS 预读列表中。
启用HPKP(引用)
HPKP是一项安全配置,他告诉浏览器将特定的加密公钥和网站关联,以此来阻止中间人攻击(MITM)。
可以这么理解如果一个CA(比如StarSSL)被伪造了并颁发了证书,这些证书都是有效的浏览器会显示 一个绿色小锁的。但是这些证书并不是真的证书,这样的话如果通过技术手段在浏览器和真实服务器之间增加一个伪造的中间服务器并且用这个伪造的证书,用户打开后依然能看到一个绿色的锁,但是网站已经被伪造过了。
这时如果启用了HPKP,只要用户正常访问过一次,浏览器就会将这个加密公钥和域名记录下来,如果发生了https下的中间人攻击浏览器就会发现网站的证书和之前记录的不一样,就会提示用户。毕竟中间人攻击并没有那么常见,用户大概率下还是正常访问的,HPKP和HSTS(Strict-Transport-Security)都是 TOFU(Trust on First Use)。
所谓的加密公钥,其实是对公钥(也就是上面说的证书)用sha256取得摘要信息,命令如下,获得 pin-sha256 为 83wPsX1JwaUELRATSTpGrI9bv1OgdUZt15aW6EqBZoE=
openssl x509 -in 1_www.chenky.com_bundle.crt -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
为了防止我的SSL失效后(比如服务器被黑)没法在继续使用了,因此要申请第二个证书作为备份,我这里是用的是沃通的免费证书,对证书命令如下,获得 pin-sha256 为 q27w+ircjhLU/DRP1lQUPMc2nVPNvBq2O4y4sOaaCTU=
openssl x509 -in 1_www.chenky.com_bundle.crt -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
将以上获得的两个pin-sha256增加到Nginx配置中:
add_header Public-Key-Pins 'pin-sha256="83wPsX1JwaUELRATSTpGrI9bv1OgdUZt15aW6EqBZoE="; pin-sha256="q27w+ircjhLU/DRP1lQUPMc2nVPNvBq2O4y4sOaaCTU="; max-age=2592000';
max-age的作用是是告诉浏览器将这个 pin-sha256 和网站关联多久,单位是秒,个人建议设置超过15天,我这里设置的是30天。
2016年12月18日补充:
HPKP
获取ECC方式的证书的pin命令如下
openssl x509 -in www.chenky.com.crt -pubkey -noout | openssl ec -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64