Nginx HTTPS 配置实践

00 前言:

博客使用 HTTPS 已经有一段时间了,最近把当时的配置过程梳理、整理了一遍,希望能对有需要的同学有所帮助。

01 概念介绍:

最近 HTTPS 是越来越流行了,前一阵子的百度,最近的淘宝、知乎,都已经开启了全站 HTTPS 的时代。HTTPS 即 Hypertext Transfer Protocol Secure,简单理解就是在 HTTP 协议上做了一层加密。具体的握手过程和加密协议以后弄透彻了再写写。

无利不起早,那么 HTTPS 的好处是什么呢?我个人觉得有以下几点:

  1. 数据传输加密,防止信息被窃取。用户的密码、认证码、个人信息、表单数据等。对于移动 APP 甚至桌面端应用程序来说,由于 Web 化的趋势,目前 HTTP 协议应用很多,传输的信息加密越来越重要。
  2. 防欺诈。当你使用 EV 级别证书(http://www.wosign.com/EVSSL/index.htm)时,浏览器网址显示和一般 SSL 证书不一样。可以对比下:https://www.paypal.com/signin/ 和 https://www.baidu.com/。使用此类证书的网址,主流的浏览器都会在地址栏显示企业的名称(支持中文),增加了网站信任度,进一步防止用户被钓鱼网站欺骗,当然证书的价格也更贵一些。
  3. 防止劫持。这点可以说是国内各大公司下决心支持 HTTPS 的主要原因了。一旦被劫持,用户访问速度会变慢,看到的内容会被篡改,比如商家在百度投放的广告被替换成竞品的广告,淘宝的商品被带上小尾巴(返利链接),甚至直接跳转到 JD。这些不光是损害用户的利益,更是直接影响公司收入。
  4. 使用新的技术。比如 SPDY/HTTP 2 的基础都是 HTTPS,新协议对移动端 APP 性能提升帮助很大:《双11手淘前端技术: H5性能最佳实践》

当然 HTTPS 也不是完全的安全,不提高安全意识还是同样会被攻击:《使用 HTTPS 的网站也能被黑客监听到数据吗?》

02 证书申请:

证书申请的大概流程是,首先在自己的服务器使用 openssl 命令(尽量使用高版本的 OpenSSL,除了能规避漏洞,还能使用更高级的密钥加密/交换算法,提升安全性和性能)生成 csr 和 key 文件,命令如下:

如命令参数所示,RSA 的加密强度是 2048 位,使用了更安全的 sha256(SHA-2)哈希算法(SHA-1算法在2016年将不被证书厂商和现代浏览器支持)。

-subj 参数指定证书申请者的信息,如果不直接使用此参数,也会有交互式的命令提示填写这些参数。此部分具体参数释义:

Country Name (2 letter code) [GB]: 输入国家地区代码,如中国的 CN

State or Province Name (full name) [Berkshire]: 地区省份

Locality Name (eg, city) [Newbury]: 城市名称

Organization Name (eg, company) [My Company Ltd]: 公司名称

Organizational Unit Name (eg, section) []: 部门名称

Common Name (eg, your name or your server’s hostname) []: 申请证书域名,如果是泛域名证书,则应该填写 *.example.com

Email Address []: 电子邮箱

生成的 csr 文件包含了主要的证书信息,key 文件主要包含了密钥交换和加密等信息(私钥,注意保存)。然后把 csr 文件提交给 CA 厂商,中间还有一些信息验证过程,一般几天后(根据证书类型不同,所需时间不一样)就会发一份邮件给你,邮件附件带有签好的证书文件 example_com.crt(注意后缀,内容也变了),同时会给你CA的证书链,CA.crt(通常是 3 个文件,包括 2 个中间证书和 1 个根证书,按照证书信任链由下到上,把文件合并cat COMODOECCDomainValidationSecureServerCA.crt COMODOECCAddTrustCA.crt AddTrustExternalCARoot.crt > CA.crt,统称CA.crt)。

03 配置详解:

后面的步骤各个 HTTP Server 就有点不一样了:

其实 Nginx 默认配置文件已经包含自签证书(关于自签证书可以参考:《给Nginx配置一个自签名的SSL证书》)的 SSL 配置项了,只要去掉注释,稍微修改下就行(我使用的是 Nginx 1.8,不同版本可能配置有差异):

这几个配置参数也很好理解。主要是填对证书文件的路径。

ssl_protocols 表示 SSL 的协议,Nginx 的配置文件已经说明不要使用 SSLv3 版本的协议(有安全问题)。其实 TLSv1 协议也不建议使用,但 IE9 默认最高只支持 TLSv1(《在 Internet Explorer 中启用 TLS 1.1 和 TLS 1.2》),为了兼容性还是支持此协议。

ssl_ciphers 参数指的是加密算法,根据自身机器 OpenSSL 的版本不一样支持的算法也不一样,设置一个安全、健壮的加密算法尤为重要(可以看见 Nginx 默认就禁用了 MD5 算法),不安全的加密算法有安全风险,而且用户打开 URL 的时候浏览器会发出警告,甚至无法打开。可以通过 openssl ciphers 命令查看系统支持的算法:

但是你可能说这不是在逗我吗?这么多!谁搞得清楚,而且还要兼顾兼容性和安全性。不要急,伟大的 mozilla 公司已经提供了一个可视化配置页面:https://mozilla.github.io/server-side-tls/ssl-config-generator/ 根据自身服务器环境和需求,简单填写几个参数就可以生成一份完美配置。

2015-12-29_000935

这时我们的配置项变成了这样(我这里后续修改过,可能和自动生成的配置文件有点点差别):

我们来看看都增加了些什么。

listen 443 ssl spdy:增加 spdy 支持,主要是提供请求复用特性,前面 HTTPS 好处阐述时有说明。目前最新版 Nginx 已支持 HTTP/2,而且 Chrome 51 开始已经不支持 spdy了,强烈建议使用 HTTP\2,直接将这行配置中的 spdy 替换为 http2 即可开启 HTTP/2:https://iyaozhen.com/nginx-http2-conf.html

ssl_dhparam: 因为默认的是使用 SHA-1 做密钥交换签名(SSL 握手时交换公钥)加密的,不太安全,推荐使用 Diffie-Hellman 算法(一种确保共享KEY安全穿越不安全网络的方法)做密钥交换。生成方法:

ssl_prefer_server_ciphers: 表示服务端加密算法优先于客户端加密算法,主要是防止降级攻击。

ssl_session_timeout、ssl_session_cache: session 缓存的相关配置,防止每次请求都要重新握手协商,提高性能。

Strict-Transport-Security(HSTS):告诉浏览器这个域名在指定的时间(max-age)内应该强制使用 HTTPS 访问,目前现代浏览器都支持。即使用户手动输入 http://example.com,浏览器也会把请求重定向到 https://example.com。而且这个跳转发生在客户端,提高了安全性和性能。不过这里不能完全取代 301/302 重定向配置,因为好像是用户必须要访问过一次 https 的域名,才会被种下这个标记。顺带说一下关于301/302 重定向,个人建议一般网站使用 301 永久重定向即可,因为这个状态会被浏览器缓存,能减轻服务端压力。但是你可能会发现淘宝使用 302 临时重定向比较多,主要还是因为这个状态码不会被浏览器长时间缓存,有利用服务端业务调整。至于 SEO 上的差别那就仁者见仁智者见智了。

X-Frame-Options:告诉浏览器本宝宝的网站不允许被别人用 iframe 标签嵌入。

X-Content-Type-Options:告诉浏览器不要猜测未知 Content-Type 的资源,主要是提高安全性。

ssl_stapling、ssl_stapling_verify:开启 (OCSP) Online Certificate Status Protocol,简单来说就是服务端代为验证证书状态。一般证书流程是需要客户端(浏览器)向 CA 机构发送请求做验证,这个时候可能遇到网络不通、延迟高等问题,造成证书验证时间过长或出错,网站访问慢甚至无法访问。主要是提高网站访问速度,特别是在国内 GFW 越来越高的情形下,用处还是很大的。我看 Nginx 官方文档,貌似还需要配置 ssl_trusted_certificate,但我没配置好像也行,可能版本有差别(具体原因可参考:《从无法开启 OCSP Stapling 说起》),完整配置方法可参考:《SSL 配置研究》中的 OCSP 配置章节。验证是否配置成功的方法:

至此基本的配置就完了,不要忘了重启 Nginx 哦。

04 测试:

跑(装)个(ge)分(逼)(https://www.ssllabs.com/ssltest/):

2015-12-29_012004

还不错 A+,页面生成的报表还包含一些兼容性测试结果和改进意见,值得关注一下。

Update 2016-07-05:

最近证书到期了,renew 时把证书从 RSA 加密换成了 ECC 加密(椭圆曲线,安全性和性能更好),这里简单记录一下:

签证书的命令和之前略有不同:

-name 参数指定具体的算法实现,openssl ecparam -list_curves 命令可以显示当前 openssl 版本(建议升级到最新版)支持的算法,同类的算法 key 的位数越大越安全,当然也更影响性能。你也可以在 https://www.ssllabs.com/ssltest/viewMyClient.html 查看自己浏览器支持的算法,辅助选择。我这里选择的是prime256v1(=secp256r1)也是 Nginx 当前版本默认的值。

生成 CSR:

和之前一样按照提示输入一些必要信息即可,然后提交 CSR 文件,几分钟新的证书就签下来了,替换掉之前的证书后 sudo nginx -s reload 重新加载配置即可。

新的证书:

2016-7-6 002509

05 参考资料:

百度全站 https FAQ- 技术宅告诉你如何搜索更安全

全站 https 时代的号角 : 大型网站的 https 实践系列 – 系列文章(4 篇),强烈建议阅读、研究

沃通SSL证书、代码签名证书、客户端数字证书安装配置指南文档下载

Nginx 配置 SSL 证书 + 搭建 HTTPS 网站教程

Module ngx_http_ssl_module

linux升级openssl和php_openssl模块

Deprecation of SHA-1 and moving to SHA-2

一些安全相关的HTTP响应头

Should disable compression when using SSL

Enable SPDY header compression

Strong SSL Security on nginx

Security/Server Side TLS

生成并成功签署 ECC SSL 证书

ECDSA sample

知识共享许可协议

4 thoughts on “Nginx HTTPS 配置实践

  1. 博主网站的 SSL证书   多少钱一年?  哪里买的?

发表评论

电子邮件地址不会被公开。 必填项已用*标注