术语“生产”是指软件生命周期中应用程序或 API 对最终用户或消费者普遍可用的阶段。相反,在“开发”阶段,您仍在积极编写和测试代码,并且应用程序不对外部访问开放。相应的系统环境分别称为“生产”和“开发”环境。
开发和生产环境通常以不同的方式设置,并且具有截然不同的要求。在开发中可以接受的东西在生产中可能不可接受。例如,在开发环境中,您可能希望详细记录错误以进行调试,而相同的行为在生产环境中可能会成为安全问题。在开发中,您无需担心可扩展性、可靠性和性能,而在生产中,这些问题变得至关重要。
注意:如果您认为在 Express 中发现了安全漏洞,请参阅 安全策略和程序。
Express 应用程序在生产环境中的安全最佳实践包括
Express 2.x 和 3.x 已经不再维护。这些版本中的安全和性能问题将不会得到修复。请勿使用它们!如果您尚未迁移到版本 4,请遵循 迁移指南。
还要确保您没有使用 安全更新页面 上列出的任何易受攻击的 Express 版本。如果您正在使用,请更新到一个稳定的版本,最好是最新版本。
如果您的应用程序处理或传输敏感数据,请使用 传输层安全 (TLS) 来保护连接和数据。此技术在数据从客户端发送到服务器之前对其进行加密,从而防止一些常见的(且容易的)攻击。虽然 Ajax 和 POST 请求可能并不明显,并且在浏览器中看起来是“隐藏”的,但它们的网络流量容易受到 数据包嗅探 和 中间人攻击 的影响。
您可能熟悉安全套接字层 (SSL) 加密。 TLS 只是 SSL 的下一个发展阶段。换句话说,如果您之前使用过 SSL,请考虑升级到 TLS。一般来说,我们建议使用 Nginx 来处理 TLS。有关在 Nginx(和其他服务器)上配置 TLS 的良好参考,请参阅 推荐的服务器配置(Mozilla Wiki)。
此外,一个方便的工具可以获取免费的 TLS 证书,那就是 Let’s Encrypt,这是一个由 互联网安全研究小组 (ISRG) 提供的免费、自动化的开放证书颁发机构 (CA)。
Helmet 可以通过适当地设置 HTTP 标头来帮助保护您的应用程序免受一些众所周知的 Web 漏洞。
Helmet 是几个较小的中间件函数的集合,这些函数设置与安全相关的 HTTP 响应标头。一些示例包括
helmet.contentSecurityPolicy
设置 Content-Security-Policy
标头。这有助于防止跨站点脚本攻击,以及其他许多事情。helmet.hsts
设置 Strict-Transport-Security
头部。这有助于强制执行与服务器的安全 (HTTPS) 连接。helmet.frameguard
设置 X-Frame-Options
头部。这提供了 点击劫持 保护。Helmet 包含其他几个中间件函数,您可以在 其文档网站 上阅读。
像任何其他模块一样安装 Helmet
$ npm install --save helmet
然后在您的代码中使用它
// ...
const helmet = require('helmet')
app.use(helmet())
// ...
它可以帮助提供额外的模糊层以减少服务器指纹识别。虽然本身不是安全问题,但提高 Web 服务器整体安全态势的一种方法是采取措施来减少指纹识别服务器上使用的软件的能力。服务器软件可以通过其对特定请求的响应方式中的怪癖来进行指纹识别。
默认情况下,Express.js 会发送 X-Powered-By
响应头标语。可以使用 app.disable()
方法禁用它
app.disable('x-powered-by')
注意:禁用 X-Powered-By 头部
不会阻止精明的攻击者确定应用程序正在运行 Express。它可能会阻止偶然的利用,但还有其他方法可以确定应用程序正在运行 Express。
Express.js 还发送它自己的格式化 404 未找到消息和自己的格式化错误响应消息。可以通过 添加您自己的未找到处理程序 和 编写您自己的错误处理程序 来更改这些消息。
// last app.use calls right before app.listen():
// custom 404
app.use((req, res, next) => {
res.status(404).send("Sorry can't find that!")
})
// custom error handler
app.use((err, req, res, next) => {
console.error(err.stack)
res.status(500).send('Something broke!')
})
为了确保 cookie 不会让您的应用程序容易受到攻击,请不要使用默认的会话 cookie 名称,并适当地设置 cookie 安全选项。
有两个主要的中间件 cookie 会话模块
express.session
中间件。express.cookieSession
中间件。这两个模块之间的主要区别在于它们保存 cookie 会话数据的方式。 express-session 中间件将会话数据存储在服务器上;它只在 cookie 本身中保存会话 ID,而不是会话数据。默认情况下,它使用内存中存储,不适合生产环境。在生产环境中,您需要设置可扩展的会话存储;请参阅 兼容的会话存储 列表。
相比之下,cookie-session 中间件实现基于 cookie 的存储:它将整个会话序列化到 cookie 中,而不是仅仅序列化会话密钥。仅当会话数据相对较小且易于编码为原始值(而不是对象)时才使用它。尽管浏览器应该支持每个 cookie 至少 4096 字节,但为了确保您不会超过限制,每个域不要超过 4093 字节的大小。此外,请注意 cookie 数据对客户端可见,因此,如果出于任何原因需要保持其安全或隐藏,则 express-session 可能是更好的选择。
使用默认的会话 cookie 名称可能会使您的应用程序容易受到攻击。所带来的安全问题类似于 X-Powered-By
:潜在的攻击者可以使用它来识别服务器并相应地针对攻击。
为了避免此问题,请使用通用的 cookie 名称;例如,使用 express-session 中间件
const session = require('express-session')
app.set('trust proxy', 1) // trust first proxy
app.use(session({
secret: 's3Cur3',
name: 'sessionId'
}))
设置以下 cookie 选项以增强安全性
secure
- 确保浏览器仅通过 HTTPS 发送 cookie。httpOnly
- 确保 cookie 仅通过 HTTP(S) 发送,而不是客户端 JavaScript,有助于防止跨站点脚本攻击。domain
- 指示 cookie 的域;使用它与请求 URL 的服务器域进行比较。如果匹配,则检查 path 属性。path
- 指示 cookie 的路径;使用它与请求路径进行比较。如果此属性和域匹配,则在请求中发送 cookie。expires
- 用于设置持久 cookie 的过期日期。以下是用 cookie-session 中间件的示例
const session = require('cookie-session')
const express = require('express')
const app = express()
const expiryDate = new Date(Date.now() + 60 * 60 * 1000) // 1 hour
app.use(session({
name: 'session',
keys: ['key1', 'key2'],
cookie: {
secure: true,
httpOnly: true,
domain: 'example.com',
path: 'foo/bar',
expires: expiryDate
}
}))
确保登录端点受到保护,以使私有数据更安全。
一种简单而强大的技术是使用两个指标阻止授权尝试
rate-limiter-flexible 包提供了使此技术变得容易且快速的工具。您可以在 文档中找到暴力破解保护的示例
使用 npm 管理应用程序的依赖项非常强大且方便。但是您使用的包可能包含可能影响您的应用程序的严重安全漏洞。您的应用程序的安全性仅与您依赖项中“最薄弱的环节”一样强大。
从 npm@6 开始,npm 会自动审查每个安装请求。您还可以使用“npm audit”来分析您的依赖项树。
$ npm audit
如果您想保持更高的安全性,请考虑使用 Snyk。
Snyk 提供 命令行工具 和 GitHub 集成,它们会根据 Snyk 的开源漏洞数据库 检查您的应用程序,以查找您的依赖项中是否存在任何已知的漏洞。按照以下步骤安装 CLI
$ npm install -g snyk
$ cd your-app
使用此命令测试您的应用程序是否存在漏洞
$ snyk test
注意 Node Security Project 或 Snyk 的安全公告,这些公告可能会影响 Express 或您的应用程序使用的其他模块。总的来说,这些数据库是有关 Node 安全知识和工具的绝佳资源。
最后,Express 应用程序(与任何其他 Web 应用程序一样)可能容易受到各种基于 Web 的攻击。熟悉已知的 Web 漏洞 并采取预防措施以避免它们。
以下是一些来自优秀的 Node.js 安全检查清单 的进一步建议。请参考该博客文章以了解有关这些建议的所有详细信息