这两篇博客是关于将Express用于生产环境的最佳实践。第一篇主要讲安全,第二篇是效率和可靠性。这里假设你已经熟悉了Node.js和网络开发的基本内容,以及生产环境的一些重要概念。
概述
术语“生产”是指在软件生命周期内,一个应用或者API可以让终端用户或者说消费者使用的场景。相对开发阶段,仍在编写和测试代码,应用是不对外开放的。对应的系统环境分别称为生产环境和开发环境。
通常开发环境和生产环境在设置上有很大差异,且需求也明显不同。经常会出现在开发中OK的事项,无法适用于生产。举个例子,在开发环境中用来排错的大量日志信息,可能会在生产环境中成为一个安全隐患。还有就是在开发环境中,不需要担心稳定性、可靠性及效率。
这篇博客就来讲讲,对于采用Express的应用上线后,一些安全方面的最佳实践。
不要使用废弃或漏洞版本的Express
使用TLS
如果需要传输敏感数据,请使用 Transport Layer Security(TLS)保护连接和数据。这个技术会在客户端向服务器发送数据之前先对其加密,因而防御一些常见的(容易的)攻击。虽然像Ajax以POST发送请求会看不到数据,像是被“隐藏”在浏览器中,但脆弱的网络传输很容易被 抓包或者被 中间人攻击。
如果你知道Secure Socket Layer(SSL)加密,那么 TLS就是下一代的SSL。换句话说,如果之前你在用SSL,可以考虑升级成TSL。一般来说,推荐使用Nginx处理TLS。这里有一篇不错的文章讲如何在Nginx(或其它服务器)上配置TLS, 推荐服务器配置(Mozilla Wiki).
还有 Let’s Encrypt用来获得TLS证书,由 网络安全研究组织(ISRG)提供:免费、自动的、开放认证授权(CA)。
使用Helmet
Helmet会帮你抵御一些熟知的,通过设置HTTP头 发起的网络攻击。
Helmet实质上是由9个中间价组成的集合,用来设置安全相关的HTTP头:
-
csp设置Content-Security-Policy,抵御跨站脚本攻击、跨站注入。
-
hidePoweredBy删除X-Powered-By。
-
hpkp增加 Public Key Pinning,用来防御利用伪造证书的中间人攻击。
-
hsts设置Strict-Transport-Security,强制(HTTP通过SSl/TLS)安全连接服务器。
-
ieNoOpen针对IE8+设置X-Download-Options。
-
noCache设置Cache-Control和Pragma,禁止客户端缓存。
-
noSniff设置X-Content-Type-Options to prevent browsers from MIME-sniffing a response away from the declared content-type.
-
frameguard设置X-Frame-Options提供 clickjacking保护。
-
xssFilter设置X-XSS-Protection激活跨站脚本(XSS)过滤。
安装Helmet模块:
npm install --save helmet
然后就像普通中间价一样使用:
...
var helmet = require('helmet');
app.use(helmet());
...
至少屏蔽X-Powered-By
如果不想用Helmet,至少要屏蔽X-Powered-By。攻击者会利用这个头(默认开启)检测是否是Express的应用,然后针对攻击。
所以,最佳实践就是调用app.disable()方法关闭它:
app.disable('x-powered-by');
如果用了Helmet,它会帮你做这件事。
使用安全cookies
为确保cookies不会出问题,不要使用默认的cookie名称,同时设置好相应的cookie安全选项。
主要有两个中间件模块:
-
express-session替代Express 3.x内置的express.session。
-
cookie-session替代Express 3.x内置的express.cookieSession。
其主要差别是如何保存cookit session数据。express-session把session数据存储在服务器上,cookie里只保存了session键。默认情况下使用内存存储,可见不是针对生产环境设计的。对于生产,需要一个可扩展的session存储,请查看 session存储兼容列表。
对应的,cookie-session实现了cookie端存储:把整个session序列化到cookie,而不是只存一个session键。这种只有在session数据很小并容易编码(基本值非对象)的情况下才适用。虽然浏览器对每份cookie提供了4096字节大小的支持,但为了保证不超出限制,最好不要超过4093字节。同样,考虑到客户端可以看到cookie数据,没任何安全可言,最好还是选择express-session。
不要使用默认的session cookie名称
使用默认的session cookie名称等于把应用开放给攻击者。所导致的安全问题和X-Powered-By类似:攻击者会针对攻击。
为此,可以采用一个没意义的cookie名称,以express-session举例:
var session = require('epress-session');
app.set('trust proxy', 1) // trust first proxy
app.use(session({
secret: 's3Cur3',
name: 'sessionId'
}));
设置cookie安全选项
如下设置cookie选项,可以增加安全性:
-
secure – 保证浏览器只能通过HTTPS发送cookie。
-
httpOnly – 保证浏览器不用客户端JavaScript发送cookie,只能通过HTTP(S)发送,这样可以不受跨站脚本攻击。
-
domain – 指定域名。先判断指定的域名和请求服务器的域名是否匹配,匹配后会进行下一个属性path的匹配。
-
path – 指定路径。路径也匹配后,发送cookie。
-
expires – 设置数据的过期时间。
这里有一段使用cookie-session例子:
var session = require('cookie-session');
var express = require('express');
var app = express();
var expiryDate = new Date(Date.now() + 60*60*1000); // 1小时
app.use(session({
name: 'session',
keys: ['key1', 'key2'],
cookie: {
secure: true,
httpOnly: true,
domain: 'example.com',
path: 'foo/bar',
expires: expiryDate
}
}));
确保依赖库是安全的
使用npm可以有效、方便的管理应用程序,但有些包可能包含严重的安全问题。整个应用的安全程度就会像“木桶效应”那样。
幸运的是,有两个工具可以保证第三方包的安全性: nsp和 requireSafe。这两个工具功能上几乎一样,都用可能会显得没必要,不过对于安全来说“宁愿多做,不要犯错”。
nsp是一个命令行工具,它会检测 Node安全项目的漏洞数据库来判定应用程序是否使用了有问题的包。安装如下:
npm i nsp -g
然后使用命令提交项目的npm-shrinkwrap.json和package.json到 nodesecurity.io进行验证。
cd your-app
nsp check
也可以用requireSafe审查模块:
npm install -g requiresafe
cd your-app
requiresafe check
额外的考虑
这里有一份相当不错的 Node.js安全检测规范。这里列一部分出来:
-
实现rate-limiting,预防暴力的认证攻击。安利一个方法 StrongLoop API Gateway,或者使用比如 express-limiter的中间件,不过这样可能需要改代码。
-
使用 csurf中间价,防御跨站伪造请求(CSRF)。
-
始终过滤用户输入,保护跨站脚本(XSS)和命令行注入空间。
-
使用参数化请求或者预设SQL语句,防御SQL注入攻击。
-
使用开源 sqlmap工具,检测SQL注入漏洞。
-
使用工具 nmap和 sslyze测试SSL配置,ciphers, keys, and renegotiation 以及证书是否有效。
-
使用 safe-regex确保正则表达式不会受到 正则表达式拒绝服务的攻击。
避免其它已知的漏洞
时刻关注 Node安全项目顾问,这是一个非常棒的关于Node安全方面的项目。
最后,像其它网络应用一样,Express应用也会遭到各种漏洞攻击。尽量熟悉 网络漏洞做好提前预防。
你可能还会对这些感兴趣…