¥Production Best Practices: Security



术语 “production” 指的是软件生命周期中的一个阶段,此时应用或 API 通常可供其终端用户或消费者使用。相比之下,在 “development” 阶段,你仍在积极编写和测试代码,并且应用不对外开放。相应的系统环境分别称为生产环境和开发环境。

¥The term “production” refers to the stage in the software lifecycle when an application or API is generally available to its end-users or consumers. In contrast, in the “development” stage, you’re still actively writing and testing code, and the application is not open to external access. The corresponding system environments are known as production and development environments, respectively.


¥Development and production environments are usually set up differently and have vastly different requirements. What’s fine in development may not be acceptable in production. For example, in a development environment you may want verbose logging of errors for debugging, while the same behavior can become a security concern in a production environment. And in development, you don’t need to worry about scalability, reliability, and performance, while those concerns become critical in production.

注意: If you believe you have discovered a security vulnerability in Express, please see 安全政策和程序.

¥<div class="doc-box doc-info" markdown="1">注意: If you believe you have discovered a security vulnerability in Express, please see Security Policies and Procedures.


生产中 Express 应用的安全最佳实践包括:

¥Security best practices for Express applications in production include:

不要使用已弃用或易受攻击的 Express 版本

¥Don’t use deprecated or vulnerable versions of Express

不再维护 Express 2.x 和 3.x。这些版本中的安全和性能问题不会得到修复。不要使用它们!如果你尚未升级到版本 4,请按照 迁移指南 进行操作。

¥Express 2.x and 3.x are no longer maintained. Security and performance issues in these versions won’t be fixed. Do not use them! If you haven’t moved to version 4, follow the migration guide.

还要确保你没有使用 安全更新页面 上列出的任何易受攻击的 Express 版本。如果是,请更新到稳定版本之一,最好是最新版本。

¥Also ensure you are not using any of the vulnerable Express versions listed on the Security updates page. If you are, update to one of the stable releases, preferably the latest.

使用 TLS

¥Use TLS

如果你的应用处理或传输敏感数据,请使用 传输层安全 (TLS) 来保护连接和数据。该技术在数据从客户端发送到服务器之前对其进行加密,从而防止一些常见(且容易)的黑客攻击。尽管 Ajax 和 POST 请求可能并不明显,并且在浏览器中看起来是 “hidden”,但它们的网络流量很容易受到 数据包嗅探中间人攻击 的影响。

¥If your app deals with or transmits sensitive data, use Transport Layer Security (TLS) to secure the connection and the data. This technology encrypts data before it is sent from the client to the server, thus preventing some common (and easy) hacks. Although Ajax and POST requests might not be visibly obvious and seem “hidden” in browsers, their network traffic is vulnerable to packet sniffing and man-in-the-middle attacks.

你可能熟悉安全套接字层 (SSL) 加密。TLS 只是 SSL 的下一步。换句话说,如果你以前使用过 SSL,请考虑升级到 TLS。一般来说,我们推荐 Nginx 来处理 TLS。有关在 Nginx(和其他服务器)上配置 TLS 的良好参考,请参阅 推荐的服务器配置 (Mozilla Wiki)

¥You may be familiar with Secure Socket Layer (SSL) encryption. TLS is simply the next progression of SSL. In other words, if you were using SSL before, consider upgrading to TLS. In general, we recommend Nginx to handle TLS. For a good reference to configure TLS on Nginx (and other servers), see Recommended Server Configurations (Mozilla Wiki).

此外,获得免费 TLS 证书的便捷工具是 让我们加密,它是 互联网安全研究组 (ISRG) 提供的免费、自动化和开放的证书颁发机构 (CA)。

¥Also, a handy tool to get a free TLS certificate is Let’s Encrypt, a free, automated, and open certificate authority (CA) provided by the Internet Security Research Group (ISRG).


¥Do Not Trust User Input

对于 Web 应用来说,最关键的安全要求之一是正确的用户输入验证和处理。这有多种形式,我们不会在这里涵盖所有形式。最终负责验证和正确处理应用接受的用户输入类型。以下是专门使用一些 express api 验证用户输入的一些示例。

¥For web applications one of the most critical security requirements is proper user input validation and handling. This comes in many forms and we will not cover all of them here. Ultimately the responsibility for validating and correctly handling the types of user input your application accepts. Here are a few examples of validating user input specifically using a few express apis.


¥Prevent Open Redirects

开放重定向是指 Web 服务器接受 url 作为用户输入(通常在 url 查询中,例如 ?url=https://example.com)并使用 res.redirect 设置 location 标头并返回 3xx 状态。执行此操作时,你的应用需要验证传入的用户输入是你支持重定向到的 URL。如果不这样做,可能会导致恶意链接将用户发送到网络钓鱼网站以及其他风险。以下是在对用户输入使用 res.redirectres.location 之前应执行的示例检查:

¥Open Redirects are when a web server accepts a url as user input (often in the url query, ex. ?url=https://example.com) and uses res.redirect to set the location header and return a 3xx status. When doing this, your application is required to validate the incoming user input is a url you support redirecting to. If you do not it can result in malicious links sending users to phishing websites among other risks. Here is an example check you should do before using res.redirect or res.location on with user input:

app.use((req, res) => {
  try {
    if (new Url(req.query.url).host === 'example.com') {
      return res.status(400).end(`Unsupported redirect to host: ${req.query.url}`)
  } catch (e) {
    return res.status(400).end(`Invalid url: ${req.query.url}`)

使用 Helmet

¥Use Helmet

Helmet 可以通过适当设置 HTTP 标头来帮助保护你的应用免受一些众所周知的 Web 漏洞的影响。

¥Helmet can help protect your app from some well-known web vulnerabilities by setting HTTP headers appropriately.

Helmet 是几个较小的中间件函数的集合,它们设置与安全相关的 HTTP 响应标头。一些例子包括:

¥Helmet is a collection of several smaller middleware functions that set security-related HTTP response headers. Some examples include:

Helmet 还包含其他几个中间件函数,你可以阅读有关 在其文档网站上 的内容。

¥Helmet includes several other middleware functions which you can read about at its documentation website.

像任何其他模块一样安装 Helmet:

¥Install Helmet like any other module:

$ npm install --save helmet


¥Then to use it in your code:

// ...

const helmet = require('helmet')

// ...


¥Reduce Fingerprinting

它可以帮助提供额外的安全层以减少服务器指纹识别。虽然本身不是安全问题,但改善 Web 服务器整体状况的一种方法是采取措施降低对服务器上使用的软件进行指纹识别的能力。服务器软件可以通过 kwirks 识别它们如何响应特定请求。

¥It can help to provide an extra layer of obsecurity to reduce server fingerprinting. Though not a security issue itself, a method to improve the overall posture of a web server is to take measures to reduce the ability to fingerprint the software being used on the server. Server software can be fingerprinted by kwirks in how they respond to specific requests.

默认情况下,Express.js 发送 X-Powered-By 响应标头横幅。这可以使用 app.disable() 方法禁用:

¥By default, Express.js sends the X-Powered-By response header banner. This can be disabled using the app.disable() method:


注意: Disabling the X-Powered-By header does not prevent a sophisticated attacker from determining that an app is running Express. It may discourage a casual exploit, but there are other ways to determine an app is running Express.

Express.js 还发送它自己的格式化 404 Not Found 消息和自己的格式化程序错误响应消息。这些可以由 添加你自己的未找到处理程序编写自己的错误处理程序 更改:

¥Express.js also sends it’s own formatted 404 Not Found messages and own formatter error response messages. These can be changed by adding your own not found handler and writing your own error handler:

// 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) => {
  res.status(500).send('Something broke!')

安全地使用 cookie

¥Use cookies securely

为确保 cookie 不会打开你的应用进行攻击,请不要使用默认会话 cookie 名称并适当设置 cookie 安全选项。

¥To ensure cookies don’t open your app to exploits, don’t use the default session cookie name and set cookie security options appropriately.

有两个主要的中间件 cookie 会话模块:

¥There are two main middleware cookie session modules:

这两个模块之间的主要区别在于它们如何保存 cookie 会话数据。express-session 中间件在服务器上存储会话数据;它只将会话 ID 保存在 cookie 本身中,而不是会话数据。默认情况下,它使用内存存储,并非为生产环境设计。在生产中,你需要设置一个可扩展的会话存储;见 兼容会话存储 名单。

¥The main difference between these two modules is how they save cookie session data. The express-session middleware stores session data on the server; it only saves the session ID in the cookie itself, not session data. By default, it uses in-memory storage and is not designed for a production environment. In production, you’ll need to set up a scalable session-store; see the list of compatible session stores.

相比之下,cookie-session 中间件实现了 cookie 支持的存储:它将整个会话序列化为 cookie,而不仅仅是会话键。仅当会话数据相对较小且易于编码为原始值(而不是对象)时才使用它。虽然浏览器应该支持每个 cookie 至少 4096 字节,但为确保不超过限制,每个域的大小不要超过 4093 字节。另外,请注意 cookie 数据将对客户端可见,因此如果有任何理由保证其安全或隐蔽,那么 express-session 可能是更好的选择。

¥In contrast, cookie-session middleware implements cookie-backed storage: it serializes the entire session to the cookie, rather than just a session key. Only use it when session data is relatively small and easily encoded as primitive values (rather than objects). Although browsers are supposed to support at least 4096 bytes per cookie, to ensure you don’t exceed the limit, don’t exceed a size of 4093 bytes per domain. Also, be aware that the cookie data will be visible to the client, so if there is any reason to keep it secure or obscure, then express-session may be a better choice.

¥Don’t use the default session cookie name

使用默认会话 cookie 名称会使你的应用容易受到攻击。提出的安全问题类似于 X-Powered-By:潜在的攻击者可以使用它来对服务器进行指纹识别并相应地进行攻击。

¥Using the default session cookie name can open your app to attacks. The security issue posed is similar to X-Powered-By: a potential attacker can use it to fingerprint the server and target attacks accordingly.

为避免此问题,请使用通用的 cookie 名称;例如使用 express-session 中间件:

¥To avoid this problem, use generic cookie names; for example using express-session middleware:

const session = require('express-session')
app.set('trust proxy', 1) // trust first proxy
  secret: 's3Cur3',
  name: 'sessionId'

¥Set cookie security options

设置以下 cookie 选项以增强安全性:

¥Set the following cookie options to enhance security:

下面是一个使用 cookie-session 中间件的例子:

¥Here is an example using cookie-session middleware:

const session = require('cookie-session')
const express = require('express')
const app = express()

const expiryDate = new Date(Date.now() + 60 * 60 * 1000) // 1 hour
  name: 'session',
  keys: ['key1', 'key2'],
  cookie: {
    secure: true,
    httpOnly: true,
    domain: 'example.com',
    path: 'foo/bar',
    expires: expiryDate


¥Prevent brute-force attacks against authorization


¥Make sure login endpoints are protected to make private data more secure.


¥A simple and powerful technique is to block authorization attempts using two metrics:

  1. 第一个是同一用户名和 IP 地址连续尝试失败的次数。

    ¥The first is number of consecutive failed attempts by the same user name and IP address.

  2. 第二个是在很长一段时间内来自 IP 地址的失败尝试次数。例如,如果某 IP 地址在一天内尝试 100 次失败,则阻止该 IP 地址。

    ¥The second is number of failed attempts from an IP address over some long period of time. For example, block an IP address if it makes 100 failed attempts in one day.

rate-limiter-flexible 包提供了使这项技术简单快捷的工具。你可以找到 文档中的暴力保护示例

¥rate-limiter-flexible package provides tools to make this technique easy and fast. You can find an example of brute-force protection in the documentation


¥Ensure your dependencies are secure

使用 npm 管理应用的依赖非常强大且方便。但是你使用的软件包可能包含严重的安全漏洞,这些漏洞也会影响你的应用。你的应用的安全性仅与依赖中的 “最脆弱的链接” 一样强。

¥Using npm to manage your application’s dependencies is powerful and convenient. But the packages that you use may contain critical security vulnerabilities that could also affect your application. The security of your app is only as strong as the “weakest link” in your dependencies.

从 npm@6 开始,npm 会自动审查每个安装请求。你也可以使用 ‘npm audit’ 来分析你的依赖树。

¥Since npm@6, npm automatically reviews every install request. Also you can use ‘npm audit’ to analyze your dependency tree.

$ npm audit

如果你想保持更安全,请考虑 Snyk

¥If you want to stay more secure, consider Snyk.

Snyk 提供 命令行工具Github 整合,用于根据 Snyk 的开源漏洞数据库 检查你的应用是否存在依赖中的任何已知漏洞。按如下方式安装 CLI:

¥Snyk offers both a command-line tool and a Github integration that checks your application against Snyk’s open source vulnerability database for any known vulnerabilities in your dependencies. Install the CLI as follows:

$ npm install -g snyk
$ cd your-app


¥Use this command to test your application for vulnerabilities:

$ snyk test


¥Avoid other known vulnerabilities

请留意可能影响 Express 或你的应用使用的其他模块的 Node 安全项目Snyk 公告。总的来说,这些数据库是有关 Node 安全的知识和工具的极好资源。

¥Keep an eye out for Node Security Project or Snyk advisories that may affect Express or other modules that your app uses. In general, these databases are excellent resources for knowledge and tools about Node security.

最后,Express 应用 - 像任何其他网络应用一样 - 可能容易受到各种基于 Web 的攻击。熟悉已知的 网络漏洞 并采取预防措施避免它们。

¥Finally, Express apps - like any other web apps - can be vulnerable to a variety of web-based attacks. Familiarize yourself with known web vulnerabilities and take precautions to avoid them.


¥Additional considerations

以下是优秀的 Node.js 安全检查表 的一些进一步建议。有关这些建议的所有详细信息,请参阅该博客文章:

¥Here are some further recommendations from the excellent Node.js Security Checklist. Refer to that blog post for all the details on these recommendations: