StrongLoop / IBMによって提供されるこの翻訳.

本書は、英語の資料と比較すると古くなっている可能性があります。最新の更新については、英語版の資料を参照してください。

実稼働環境におけるベスト・プラクティス: セキュリティー

概説

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.

Note

If you believe you have discovered a security vulnerability in Express, please see Security Policies and Procedures.

本番環境でのExpressアプリケーションのセキュリティのベスト・プラクティスは次のとおりです。

非推奨バージョンや脆弱なバージョンの Express を使用しない

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 or consider Commercial Support Options.

また、セキュリティー更新ページにリストされている脆弱な Express バージョンを使用していないことを確認してください。使用している場合は、安定しているリリース (最新を推奨します) に更新してください。 If you are, update to one of the stable releases, preferably the latest.

TLS を使用する

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.

You may be familiar with Secure Socket Layer (SSL) encryption. Secure Socket Layer (SSL) 暗号化については理解されていると思います。TLS は、単に SSL が進化したものです。つまり、以前に SSL を使用していた場合は、TLS へのアップグレードを検討してください。一般に、TLS を処理するために Nginx を使用することをお勧めします。Nginx (およびその他のサーバー) で TLS を構成するための解説については、Recommended Server Configurations (Mozilla Wiki) を参照してください。 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).

また、Let’s Encrypt は、無料の TLS 証明書を取得するための便利なツールです。このツールは、Internet Security Research Group (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. 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.

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.

Here is an example of checking URLs before using res.redirect or res.location:

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)
})

Helmet を使用する

Helmet は、HTTP ヘッダーを適切に設定することによって、いくつかの既知の Web の脆弱性からアプリケーションを保護します。

Helmet is a middleware function that sets security-related HTTP response headers. Helmet sets the following headers by default:

Each header can be configured or disabled. To read more about it please go to its documentation website.

その他のモジュールと同様に Helmet をインストールします。

$ npm install helmet

次に、コードで使用します。

// ...

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.

そのため、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. It may discourage a casual exploit, but there are other ways to determine an app is running Express.

Express also sends its own formatted “404 Not Found” messages and 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) => {
  console.error(err.stack)
  res.status(500).send('Something broke!')
})

Cookie を介してアプリケーションが悪用されないように、デフォルトの セッション Cookie 名を使用しないでください。また、Cookie のセキュリティー・オプションを適切に設定してください。

主なミドルウェア Cookie セッション・モジュールが 2 つあります。

The main difference between these two modules is how they save cookie session data. これらの 2 つのモジュールの主な違いは、Cookie セッション・データの保存方法です。express-session ミドルウェアは、セッション・データをサーバーに保管します。セッション・データではなく、Cookie 自体の中にあるセッション ID のみを保存します。デフォルトで、メモリー内のストレージを使用し、実稼働環境向けには設計されていません。実稼働環境では、スケーラブルなセッション・ストアをセットアップする必要があります。互換性のあるセッション・ストアのリストを参照してください。 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. 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.

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 ミドルウェアを使用します。

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

セキュリティーを強化するために、以下の 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
  }
}))

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.
  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.

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

依存関係がセキュアであることを確認する

npm を使用したアプリケーションの依存関係の管理は、強力で便利な方法です。ただし、使用するパッケージに、アプリケーションにも影響を与える可能性がある重大なセキュリティーの脆弱性が含まれている可能性があります。アプリケーションのセキュリティーの強さは、依存関係の中で「最も弱いリンク」程度でしかありません。 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.

Since npm@6, npm automatically reviews every install request. npm@6以降、npmはすべてのインストール要求を自動的に確認します。また、’npm audit’を使用して依存関係ツリーを分析することもできます。

$ npm audit

よりセキュアな状態を保ちたい場合は、Snykを検討してください。

Snykは、Snykのオープンソース脆弱性データベースに対して、依存関係の既知の脆弱性に対するアプリケーションをチェックするコマンドラインツールGithub integrationを提供しています。 次のようにCLIをインストールします。 Install the CLI as follows:

$ npm install -g snyk
$ cd your-app

このコマンドを使用して、アプリケーションの脆弱性をテストします。

$ snyk test

その他の既知の脆弱性を回避する

アプリケーションで使用する Express やその他のモジュールに影響を与える可能性がある Node Security Project のアドバイザリーに常に注意してください。一般に、Node Security Project は、Node のセキュリティーに関する知識とツールの優れたリソースです。 In general, these databases are excellent resources for knowledge and tools about Node security.

最後に、Express アプリケーションは、その他の Web アプリケーションと同様、さまざまな Web ベースの攻撃に対して脆弱になりえます。既知の Web の脆弱性をよく理解して、それらを回避するための予防措置を取ってください。 Familiarize yourself with known web vulnerabilities and take precautions to avoid them.

その他の考慮事項

次に、優れた Node.js セキュリティー・チェックリストに記載されているその他の推奨事項をリストします。これらの推奨事項の詳細については、ブログの投稿を参照してください。 Refer to that blog post for all the details on these recommendations:

Edit this page