Jerry Qu 博客 Nginx 配置之安全篇

本文转载自 本博客 Nginx 配置之性能篇

之前有细心的朋友问我,为什么你的博客副标题是「专注 WEB 端开发」,是不是少了「前端」的「前」。我想说的是,尽管我从毕业到现在七年左右的时间一直都在专业前端团队从事前端相关工作,但这并不意味着我的知识体系就必须局限于前端这个范畴内。现在比较流行「全栈工程师」的概念,我觉得全栈意味着一个项目中,各个岗位所需要的技能你都具备,但并不一定意味着你什么都需要做。你需要做什么,更多是由能力、人员配比以及成本等各个因素所决定。尽管我现在的工作职责是在 WEB 前端领域,但是我的关注点在整个 WEB 端。

我接触过的有些前端朋友,从一开始就把自己局限在一个很小的范围之中,这在大公司到也无所谓,大公司分工明确,基础设施齐全,你只要做好自己擅长的那部分就可以了。但是当他们进入创业公司之后,会发现一下子来了好多之前完全没有接触过的东西,十分被动。

去年我用 Lua + OpenResty 替换了线上千万级的 PHP + Nginx 服务,至今稳定运行,算是前端之外的一点尝试。我一直认为学习任何知识很重要的一点是实践,所以我一直都在折腾我的 VPS,进行各种 WEB 安全、优化相关的尝试。我打算从安全和性能两方面介绍一下本博客所用 Nginx 的相关配置,今天先写安全相关的。

隐藏不必要的信息

大家可以看一下我的博客请求响应头,有这么一行 server: nginx,说明我用的是 Nginx 服务器,但并没有具体的版本号。由于某些 Nginx 漏洞只存在于特定的版本,隐藏版本号可以提高安全性。这只需要在配置里加上这个就可以了:

server_tokens   off;

如果想要更彻底隐藏所用 Web Server,可以修改 Nginx 源码,把 Server Name 改掉再编译,具体步骤可以自己搜索。需要提醒的是:如果你的网站支持 SPDY,只改动网上那些文章写到的地方还不够,跟 SPDY 有关的代码也要改。更简单的做法是改用 Tengine 这个 Nginx 的增强版,并指定 server_tag 为 off 或者任何想要的值就可以了。另外,既然想要彻底隐藏 Nginx,404、500 等各种出错页也需要自定义。

同样,一些 WEB 语言或框架默认输出的 x-powered-by 也会泄露网站信息,他们一般都提供了修改或移除的方法,可以自行查看手册。如果部署上用到了 Nginx 的反向代理,也可以通过 proxy_hide_header 指令隐藏它:

proxy_hide_header        X-Powered-By;

禁用非必要的方法

由于我的博客只处理了 GET、POST 两种请求方法,而 HTTP/1 协议还规定了 TRACE 这样的方法用于网络诊断,这也可能会暴露一些信息。所以我针对 GET、POST 以及 HEAD 之外的请求,直接返回了 444 状态码(444 是 Nginx 定义的响应状态码,会立即断开连接,没有响应正文)。具体配置是这样的:

if ($request_method !~ ^(GET|HEAD|POST)$ ) {
    return    444;
}

合理配置响应头

我的博客是由自己用 ThinkJS 写的 Node 程序提供服务,Nginx 通过 proxy_pass 把请求反向代理给 Node 绑定的 IP 和端口。在最终输出时,我给响应增加了以下头部:

add_header  Strict-Transport-Security  "max-age=31536000";
add_header  X-Frame-Options  deny;
add_header  X-Content-Type-Options  nosniff;
add_header  Content-Security-Policy  "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://a.disquscdn.com; img-src 'self' data: https://www.google-analytics.com; style-src 'self' 'unsafe-inline'; frame-src https://disqus.com";

Strict-Transport-Security(简称为 HSTS)可以告诉浏览器,在指定的 max-age 内,始终通过 HTTPS 访问我的博客。即使用户自己输入 HTTP 的地址,或者点击了 HTTP 链接,浏览器也会在本地替换为 HTTPS 再发送请求。另外由于我的证书不支持多域名,我没有加上 includeSubDomains。关于 HSTS 更多信息,可以查看我之前的介绍

X-Frame-Options 用来指定此网页是否允许被 iframe 嵌套,deny 就是不允许任何嵌套发生。关于这个响应头的更多介绍可以看这里

X-Content-Type-Options 用来指定浏览器对未指定或错误指定 Content-Type 资源真正类型的猜测行为,nosniff 表示不允许任何猜测。这部分内容更多介绍见这里

Content-Security-Policy(简称为 CSP)用来指定页面可以加载哪些资源,主要目的是减少 XSS 的发生。我允许了来自本站、disquscdn 的外链 JS,还允许内联 JS,以及在 JS 中使用 eval;允许来自本站和 google 统计的图片,以及内联图片(Data URI 形式);允许本站外链 CSS 以及内联 CSS;允许 iframe 加载来自 disqus 的页面。对于其他未指定的资源,都会走默认规则 self,也就是只允许加载本站的。关于 CSP 的详细介绍请看这里

之前的博客中,我还介绍过 X-XSS-Protection 这个响应头,也可以用来防范 XSS。不过由于有了 CSP,所以我没配置它。

需要注意的是,以上这些响应头现代浏览器才支持,所以并不是说加上他们,网站就可以不管 XSS,万事大吉了。但是鉴于低廉的成本,还是都配上。

HTTPS 安全配置

启用 HTTPS 并正确配置了证书,意味着数据传输过程中无法被第三者解密或修改。有了 HTTPS,也得合理配置好 Web Server,才能发挥最大价值。我的博客关于 HTTPS 这一块有以下配置:

ssl_certificate      /home/jerry/ssl/server.crt;
ssl_certificate_key  /home/jerry/ssl/server.key;
ssl_dhparam          /home/jerry/ssl/dhparams.pem;

ssl_ciphers          ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:DES-CBC3-SHA;

ssl_prefer_server_ciphers  on;

ssl_protocols        TLSv1 TLSv1.1 TLSv1.2;

最终效果是我的博客在 ssllabs 的测试中达到了 A+,如下图:

如何配置 ssl_ciphers 可以参考这个网站。需要注意的是,这个网站默认提供的加密方式安全性较高,一些低版本客户端并不支持,例如 IE9-、Android2.2- 和 Java6-。如果需要支持这些老旧的客户端,需要点一下网站上的「Yes, give me a ciphersuite that works with legacy / old software」链接。

另外,我在 ssl_ciphers 最开始加上了 CHACHA20,这是因为我的 Nginx 支持了 CHACHA20_POLY1305 加密算法,这是由 Google 开发的新一代加密方式,它有两方面优势:更好的安全性和更好的性能(尤其是在移动和可穿戴设备上)。下面有一张移动平台上它与 AES-GCM 的加密速度对比图(via):

启用 CHACHA20_POLY1305 最简单的方法是在编译 Nginx 时,使用 LibreSSL 代替 OpenSSL。下面是用 Chrome 访问我的博客时,点击地址栏小锁显示的信息,可以看到加密方式使用的就是 CHACHA20_POLY1305:

关于 CHACHA20_POLY1305 安全性和性能的详细介绍可以查看本文

补充:使用 CHACHA20_POLY1305 的最佳实践是「仅针对不支持 AES-NI 的终端使用 CHACHA20 算法,否则使用 AES-GCM」。关于这个话题的详细解释和配置方法,请参考我的这篇文章:使用 BoringSSL 优化 HTTPS 加密算法选择

关于 ssl_dhparam 的配置,可以参考这篇文章:Guide to Deploying Diffie-Hellman for TLS

SSLv3 已被证实不安全,所以在 ssl_protocols 指令中,我并没有包含它。

ssl_prefer_server_ciphers 配置为 on,可以确保在 TLSv1 握手时,使用服务端的配置项,以增强安全性。

好了,本文先就这样,后面再写跟性能有关的配置。

原文链接:https://imququ.com/post/my-nginx-conf-for-security.html前往原文评论 »

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏一体化运维管控平台

HTTPS 证书配置一劳永逸

HTTPS 是在 HTTP 协议基础之上加了一层 SSL/TLS 安全认证机制,原理功能概括一句即客户端和服务端在非对称密钥通讯中交换临时对称密钥进行的加密数据...

1.5K70
来自专栏吴伟祥

聊一聊HTTPS和SSL/TLS 转

HTTPS(Hyper Text Transfer Protocol over Secure Socket Layer)简单的讲就是HTTP的安全版本。即HTT...

6710
来自专栏阮一峰的网络日志

HTTPS的七个误解(译文)

我使用的工具主要有两个,在Firefox中是Firebug,在IE中是Fiddler。但是,一直听别人说,付费软件HttpWatch是这方面最好的工具。

21520
来自专栏网络

突破封闭 Web 系统的技巧之正面冲锋

在互联网安全服务公司乙方工作的人或者进行 SRC 众测等相关渗透测试时,经常碰到客户只给一个 "xxx信息管理系统"、"xxx平台"之类的一个 Web 登录界面...

293110
来自专栏前端儿

HTTPS 概述

HTTPS(Secure Hypertext Transfer Protocol)安全超文本传输协议 它是一个安全通信通道,它基于HTTP开发,用于在客户计算机...

27520
来自专栏源码之家

使用神器快速破解Zend及ionCube加密的php文件

2.4K40
来自专栏前端黑板报

软件工程师需要了解的网络知识:从铜线到HTTP(五)—— HTTP 和 HTTPS

JohnLui:程序员,Swift Contributor,正在写《iOS 可视化编程与 Auto Layout》 HTTP 在以前的文章中,我大力推荐过《图解...

38770
来自专栏FreeBuf

一封伪造邮件引发的“探索”(涉及钓鱼邮件、SPF和DKIM等)

0x00. 引言 我用swaks 发送一封以我们公司CTO为显示发件人(腾讯企业邮箱)的伪造邮件给我的一个同事,邮件的内容就是让这位同事去CTO的办公司一趟,没...

1.4K60
来自专栏Golang语言社区

Go语言·Web调优详解

Go1.8将要来了,这种格局即将被打破了! 我们最近尝试性的将Go1.8编译的服务暴漏到了外网,结果发现crypto/tls 和net/http都得到了极大的提...

39290
来自专栏小樱的经验随笔

记一道明文破解的漫长斗争史

相信很多看过我博客的朋友,都记得我曾经写过 Zip 加密文件破解的文章,如果有没看过的读者朋友们参看这里:https://www.cnblogs.com/ECJ...

32250

扫码关注云+社区

领取腾讯云代金券