「実稼働」という用語は、ソフトウェアのライフサイクルにおいて、アプリケーションや API をエンド・ユーザーまたはコンシューマーが広く使用できる段階を指します。対照的に、「開発」段階では、まだコードの作成とテストを積極的に行っていて、アプリケーションへの外部アクセスは不可能です。対応するシステム環境は、それぞれ実稼働 環境と開発 環境と呼ばれています。
開発環境と実稼働環境は通常、別々にセットアップされ、それぞれの要件は大きく異なっています。開発環境では許可されることが、実稼働環境では許可されないことがあります。例えば、開発環境ではデバッグのためにエラーの詳細なロギングを実行できますが、同じ動作が実稼働環境ではセキュリティー上の問題となります。開発環境では、スケーラビリティー、信頼性、パフォーマンスについて心配する必要はありませんが、それらは実稼働環境では重大な問題となります。
Note
If you believe you have discovered a security vulnerability in Express, please see Security Policies and Procedures.
本番環境でのExpressアプリケーションのセキュリティのベスト・プラクティスは次のとおりです。
Express 2.x および 3.x は保守されなくなりました。これらのバージョンにおけるセキュリティーとパフォーマンスの問題は修正されません。これらのバージョンを決して使用しないでください。まだバージョン 4 に移行していない場合は、マイグレーション・ガイドに従ってください。
また、セキュリティー更新ページにリストされている脆弱な Express バージョンを使用していないことを確認してください。使用している場合は、安定しているリリース (最新を推奨します) に更新してください。
アプリケーションが機密データを処理または送信する場合は、Transport Layer Security (TLS) を使用して、接続とデータを保護してください。このテクノロジーは、データをクライアントからサーバーへの送信前に暗号化するため、一般的 (容易) なハッキングを防止します。Ajax と POST 要求は明白ではなく、ブラウザーに対して「非表示」になっているように見えますが、そのネットワーク・トラフィックは、パケットのスニッフィングと中間者攻撃に対して脆弱です。
Secure Socket Layer (SSL) 暗号化については理解されていると思います。TLS は、単に SSL が進化したものです。つまり、以前に SSL を使用していた場合は、TLS へのアップグレードを検討してください。一般に、TLS を処理するために Nginx を使用することをお勧めします。Nginx (およびその他のサーバー) で TLS を構成するための解説については、Recommended Server Configurations (Mozilla Wiki) を参照してください。
また、Let’s Encrypt は、無料の TLS 証明書を取得するための便利なツールです。このツールは、Internet Security Research Group (ISRG) が提供する、無料の自動的かつオープンな認証局 (CA) です。
Helmet は、HTTP ヘッダーを適切に設定することによって、いくつかの既知の Web の脆弱性からアプリケーションを保護します。
Helmet は、実際には、セキュリティー関連の HTTP ヘッダーを設定する 9 個の小さなミドルウェア関数の単なる集合です。
Content-Security-Policy
ヘッダーを設定します。X-Powered-By
ヘッダーを削除します。Strict-Transport-Security
ヘッダーを設定します。X-Download-Options
を設定します。Cache-Control
ヘッダーと Pragma ヘッダーを設定します。X-Content-Type-Options
を設定します。X-Frame-Options
ヘッダーを設定します。X-XSS-Protection
を設定します。その他のモジュールと同様に Helmet をインストールします。
$ npm install --save helmet
次に、コードで使用します。
// ...
const helmet = require('helmet')
app.use(helmet())
// ...
Helmet を使用しない場合は、少なくとも X-Powered-By
ヘッダーを無効にしてください。アタッカーが、(デフォルトで有効になっている) このヘッダーを使用して、Express を実行しているアプリケーションを検出し、具体的に対象を絞った攻撃を開始する可能性があります。
そのため、app.disable()
メソッドを使用してこのヘッダーをオフにすることがベスト・プラクティスです。
app.disable('x-powered-by')
helmet.js
を使用する場合は、この操作が自動的に実行されます。
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.
Cookie を介してアプリケーションが悪用されないように、デフォルトの セッション Cookie 名を使用しないでください。また、Cookie のセキュリティー・オプションを適切に設定してください。
主なミドルウェア Cookie セッション・モジュールが 2 つあります。
express.session
ミドルウェアに取って代わります。express.cookieSession
ミドルウェアに取って代わります。これらの 2 つのモジュールの主な違いは、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 がクライアント JavaScript ではなく、HTTP(S) のみを介して送信されるようにして、クロスサイト・スクリプティング攻撃から保護します。domain
- Cookie のドメインを指定します。URL が要求されているサーバーのドメインとの比較に使用します。一致する場合は、次にパス属性を確認します。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
}
}))
npm を使用したアプリケーションの依存関係の管理は、強力で便利な方法です。ただし、使用するパッケージに、アプリケーションにも影響を与える可能性がある重大なセキュリティーの脆弱性が含まれている可能性があります。アプリケーションのセキュリティーの強さは、依存関係の中で「最も弱いリンク」程度でしかありません。
npm@6以降、npmはすべてのインストール要求を自動的に確認します。また、’npm audit’を使用して依存関係ツリーを分析することもできます。
$ npm audit
よりセキュアな状態を保ちたい場合は、Snykを検討してください。
Snykは、Snykのオープンソース脆弱性データベースに対して、依存関係の既知の脆弱性に対するアプリケーションをチェックするコマンドラインツールとGithub integrationを提供しています。 次のようにCLIをインストールします。
$ npm install -g snyk
$ cd your-app
このコマンドを使用して、アプリケーションの脆弱性をテストします。
$ snyk test
アプリケーションで使用する Express やその他のモジュールに影響を与える可能性がある Node Security Project のアドバイザリーに常に注意してください。一般に、Node Security Project は、Node のセキュリティーに関する知識とツールの優れたリソースです。
最後に、Express アプリケーションは、その他の Web アプリケーションと同様、さまざまな Web ベースの攻撃に対して脆弱になりえます。既知の Web の脆弱性をよく理解して、それらを回避するための予防措置を取ってください。
次に、優れた Node.js セキュリティー・チェックリストに記載されているその他の推奨事項をリストします。これらの推奨事項の詳細については、ブログの投稿を参照してください。