Production Best Practices: Security生产最佳实践:安全

Overview

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. 术语“生产”是指软件生命周期中应用程序或API通常可供最终用户或消费者使用的阶段。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.在开发中,您不需要担心可扩展性、可靠性和性能,而这些问题在生产中变得至关重要。

Note

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版本

Express 2.x and 3.x are no longer maintained. Security and performance issues in these versions won’t be fixed. Express 2x和3x不再维护。这些版本中的安全和性能问题将不会得到修复。Do not use them! If you haven’t moved to version 4, follow the migration guide or consider Commercial Support Options.不要使用它们!如果您尚未迁移到版本4,请遵循迁移指南或考虑商业支持选项

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.还要确保您没有使用安全更新页面上列出的任何易受攻击的Express版本。如果是,请更新到稳定版本之一,最好是最新版本。

Use 使用TLS

If your app deals with or transmits sensitive data, use Transport Layer Security (TLS) to secure the connection and the data. 如果您的应用程序处理或传输敏感数据,请使用传输层安全性(TLS)来保护连接和数据。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.虽然Ajax和POST请求可能并不明显,而且似乎“隐藏”在浏览器中,但它们的网络流量很容易受到数据包嗅探中间人攻击

You may be familiar with Secure Socket Layer (SSL) encryption. TLS is simply the next progression of SSL. 您可能熟悉安全套接字层(SSL)加密。TLS只是SSL的下一个发展In other words, if you were using SSL before, consider upgrading to TLS. In general, we recommend Nginx to handle TLS. 换句话说,如果您以前使用SSL,请考虑升级到TLS。一般来说,我们建议Nginx处理TLS。For a good reference to configure TLS on Nginx (and other servers), see Recommended Server Configurations (Mozilla Wiki).有关在Nginx(和其他服务器)上配置TLS的良好参考,请参阅推荐的服务器配置(Mozilla Wiki)

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).此外,获得免费TLS证书的一个方便的工具是Let's Encrypt,这是一个由互联网安全研究小组(ISRG)提供的免费、自动化和开放的证书颁发机构(CA)。

Do not trust user input不信任用户输入

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.对于web应用程序,最关键的安全要求之一是正确的用户输入验证和处理。这有很多种形式,我们在这里不会一一介绍。 Ultimately, the responsibility for validating and correctly handling the types of user input your application accepts is yours.最终,验证和正确处理应用程序接受的用户输入类型的责任在于您。

Prevent open redirects阻止打开重定向

An example of potentially dangerous user input is an open redirect, where an application accepts a URL as user input (often in the URL query, for example ?url=https://example.com) and uses res.redirect to set the location header and return a 3xx status.潜在危险的用户输入的一个例子是开放重定向,其中应用程序接受URL作为用户输入(通常在URL查询中,例如?url=https://example.com),并使用res.redirect设置location标头并返回3xx状态。

An application must validate that it supports redirecting to the incoming URL to avoid sending users to malicious links such as phishing websites, among other risks.应用程序必须验证它是否支持重定向到传入的URL,以避免将用户发送到钓鱼网站等恶意链接以及其他风险。

Here is an example of checking URLs before using res.redirect or res.location:以下是在使用res.redirectres.location之前检查URL的示例:

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}`)
  }
  res.redirect(req.query.url)
})

Use 使用Helmet

Helmet can help protect your app from some well-known web vulnerabilities by setting HTTP headers appropriately.通过适当设置HTTP标头,可以帮助保护您的应用程序免受一些众所周知的web漏洞的攻击。

Helmet is a middleware function that sets security-related HTTP response headers. Helmet sets the following headers by default:Helmet是一个中间件函数,用于设置与安全相关的HTTP响应头。默认情况下,Helmet设置以下标题:

Each header can be configured or disabled. To read more about it please go to its documentation website.每个标头都可以配置或禁用。要了解更多信息,请访问其文档网站

Install Helmet like any other module:像安装其他模块一样安装头盔:

$ npm install helmet

Then to use it in your code:然后在代码中使用它:

// ...

const helmet = require('helmet')
app.use(helmet())

// ...

Reduce fingerprinting减少指纹识别

It can help to provide an extra layer of security to reduce the ability of attackers to determine the software that a server uses, known as “fingerprinting.” 它可以帮助提供额外的安全层,以降低攻击者确定服务器使用的软件的能力,即“指纹识别”Though not a security issue itself, reducing the ability to fingerprint an application improves its overall security posture. 虽然这本身不是安全问题,但降低对应用程序进行指纹识别的能力可以改善其整体安全状况。 Server software can be fingerprinted by quirks in how it responds to specific requests, for example in the HTTP response headers.服务器软件可以通过其对特定请求的响应方式(例如HTTP响应头)的怪癖来识别指纹。

By default, Express sends the X-Powered-By response header that you can disable using the app.disable() method:默认情况下,Express会发送X-Powered-By响应标头,您可以使用app.disable()方法禁用该标头:

app.disable('x-powered-by')

Note

Disabling the X-Powered-By header does not prevent a sophisticated attacker from determining that an app is running Express. 禁用X-Powered-By标头并不能阻止老练的攻击者确定应用程序正在运行Express。It may discourage a casual exploit, but there are other ways to determine an app is running Express.它可能会阻止随意利用,但还有其他方法可以确定应用程序是否正在运行Express。

Express also sends its own formatted “404 Not Found” messages and formatter error response messages. Express还发送自己格式化的“404 Not Found”消息和格式化程序错误响应消息。These can be changed by adding your own not found handler and writing your own error handler:可以通过添加自己的not found处理程序编写自己的错误处理程序来更改这些设置:

// 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!')
})

Use cookies securely安全地使用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不会使您的应用程序被漏洞利用,请不要使用默认会话cookie名称,并适当设置cookie安全选项。

There are two main middleware cookie session modules:有两个主要的中间件cookie会话模块:

The main difference between these two modules is how they save cookie session data. 这两个模块之间的主要区别在于它们如何保存cookie会话数据。The express-session middleware stores session data on the server; it only saves the session ID in the cookie itself, not session data. express-session中间件将会话数据存储在服务器上;它只将会话ID保存在cookie本身中,而不是会话数据。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.在生产环境中,您需要设置一个可扩展的会话存储;请参阅兼容会话存储列表。

In contrast, cookie-session middleware implements cookie-backed storage: it serializes the entire session to the cookie, rather than just a session key. 相比之下,cookie-session中间件实现了cookie支持的存储:它将整个会话序列化为cookie,而不仅仅是会话键。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. 虽然浏览器应该支持每个cookie至少4096字节,但为了确保不超过限制,每个域的大小不要超过4093字节。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.此外,请注意,cookie数据对客户端是可见的,因此如果有任何理由保持其安全性或隐蔽性,那么express-session可能是更好的选择。

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名称可能会使您的应用程序受到攻击。所提出的安全问题类似于X-Powered-By:潜在的攻击者可以使用它对服务器进行指纹识别,并相应地针对攻击。

To avoid this problem, use generic cookie names; for example using express-session middleware:为避免此问题,请使用通用cookie名称;例如使用express-session中间件:

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

Set the following cookie options to enhance security:设置以下cookie选项以增强安全性:

Here is an example using cookie-session middleware:以下是一个使用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
  }
}))

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. The number of consecutive failed attempts by the same user name and IP address.同一用户名和IP地址连续失败的尝试次数。
  2. The 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.在很长一段时间内从IP地址尝试失败的次数。例如,如果一个IP地址在一天内尝试了100次失败,则将其阻止。

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确保您的依赖关系是安全的

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来管理应用程序的依赖关系是强大而方便的。但是,您使用的软件包可能包含关键的安全漏洞,这些漏洞也可能影响您的应用程序。应用程序的安全性取决于依赖关系中的“最薄弱环节”。

Since npm@6, npm automatically reviews every install request. Also, you can use npm audit to analyze your dependency tree.自从npm@6npm会自动审查每个安装请求。此外,您还可以使用npm audit来分析您的依赖树。

$ npm audit

If you want to stay more secure, consider Snyk.如果你想保持更安全,可以考虑Snyk

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:Snyk提供了一个命令行工具和一个Github集成,可以根据Snyk的开源漏洞数据库检查您的应用程序的依赖关系中的任何已知漏洞。按如下方式安装CLI:

$ npm install -g snyk
$ cd your-app

Use this command to test your application for vulnerabilities:使用此命令测试您的应用程序是否存在漏洞:

$ snyk test

Avoid other known vulnerabilities避免其他已知漏洞

Keep an eye out for Node Security Project or Snyk advisories that may affect Express or other modules that your app uses. 请留意Node Security ProjectSnyk的公告,这些公告可能会影响您的应用程序使用的Express或其他模块。In general, these databases are excellent resources for knowledge and tools about Node security.一般来说,这些数据库是关于节点安全的知识和工具的绝佳资源。

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.最后,Express应用程序——就像任何其他网络应用程序一样——可能容易受到各种基于网络的攻击。熟悉已知的网络漏洞,并采取预防措施来避免它们。

Additional considerations其他注意事项

Here are some further recommendations from the excellent Node.js Security Checklist. Refer to that blog post for all the details on these recommendations:以下是优秀的Node.js安全检查表中的一些进一步建议。有关这些建议的所有详细信息,请参阅该博客文章: