In this article
Node.jsのセキュリティを守るベストプラクティス10選
Node.jsとは?
Node.jsは、オープンソースのクロスプラットフォームWebアプリケーション開発プラットフォームです。ChromeのV8エンジン上に構築されたJavaScriptランタイムで、開発者はスケーラブルなWebアプリケーションをすばやく簡単に構築できます。
Node.jsのセキュリティとは?
Node.js自体は安全なプラットフォームですが、エコシステム内のサードパーティ製オープンソースパッケージの多くは安全とは限りません。これらのパッケージはNode Package Manager(NPM)を通じて利用され、さまざまな脆弱性や、その他のNode.jsのライセンスおよびセキュリティリスクの影響を受ける可能性があります。Node.jsのコードベースにはこうしたパッケージが何千も含まれていることがあり、アプリケーションを多くのリスクにさらします。
Node.jsのセキュリティを確保するべき理由
NPM(通常はNode.jsランタイムと併用されます)は、最大規模のオープンソースパッケージエコシステムの一つです。オープンソース技術は、サイバーセキュリティ上の大きな懸念になり得ます。実際、Snykのオープンソースセキュリティの現状レポートによると、平均的なプロジェクトには49件の脆弱性があり、79個の直接依存関係にまたがっています。さらに、GitHubの開発者が実施したセキュリティ実験では、NPMパッケージの14%にアクセスでき、依存関係の連鎖を通じてさらに54%にもアクセスできる可能性があることが明らかになりました。
このことから、Node.jsは、ハッカーに攻撃される可能性を考慮しなくてよいほど安全ではないことがわかります。こうしたNPMセキュリティのベストプラクティス10選に加え、Node.jsで構築したアプリケーションの安全性を確保するため、以下のプラクティスもおすすめします。
Node.jsの安全性を保つベストプラクティス10選
Node.jsでよくあるリスクに対処するには、重要なベストプラクティスを実践する必要があります。ここでは、Node.jsでよくあるセキュリティ上の落とし穴を避けるために役立つ、特に重要なベストプラクティスを10個ご紹介します。
1. ログ記録と監視を設定する
Node.jsのセキュリティを継続的に確保するうえで、ログ記録と監視は非常に重要です。ログを監視することで、アプリケーションで何が起きているかを把握し、不審な点を調査できます。記録すべき重要なログレベルには、info、error、warn、debugがあります。手作業を減らすには、Bunyanやtoobusy-jsなどのモジュールを活用して、ログ記録と監視を自動化できます。
2. 強固な認証ポリシーを導入する
先ほど挙げた攻撃の可能性のいくつかは、悪意のある攻撃者がユーザー認証を回避したり、悪用したりするものだとお気づきかもしれません。強固な認証ポリシーを導入することは、こうした攻撃者に対する重要な防御策です。認証に関するガイドラインをいくつかご紹介します。
多要素認証(MFA)とシングルサインオン(SSO)を必須にする
Node.jsのcryptoライブラリよりも、ScryptまたはBcryptライブラリを使用する
一貫したセッション管理ポリシーを導入する
強力なユーザーパスワードを必須にする
ログイン失敗回数を制限する
3. イベントループのブロックを避ける
イベントループやワーカープールのスレッドで重い処理を実行すると、他のクライアントからのリクエストへの応答が止まり、スループットに悪影響を及ぼす可能性があります。スレッドがブロックされないようにする方法をいくつかご紹介します。
JavaScriptのコールバックをすばやく実行できるようにします。
引数にかかわらず処理ステップ数を一定に保ち、コールバックの複雑さを抑えます。これにより、キュー内のすべてのクライアントに公平に処理の機会を与えられます。
複雑なタスクがある場合は、入力を制限し、長すぎる入力を拒否します。入力を制限すると、最悪のケースの入力にかかる時間を基準に処理が実行されるため、スレッドのブロックを防げます(もちろん、まず最悪のケースでもスレッドがブロックされない程度に処理時間が短いことを確認してください)。
暗号化、圧縮、ファイルシステム、子プロセスの各モジュールで同期APIを使用しないでください。これらの処理は完了までに時間がかかり、イベントループをブロックする可能性があります。
4. 安全なエラー処理
エラーに対処できるようにコードを準備しておくことで、アプリケーションのパフォーマンスやセキュリティに関する多くの問題を軽減できます。プログラムの不具合を防ぐためのベストプラクティスをご紹介します。
非同期エラーをコールバックで管理するのではなく、信頼できるPromiseライブラリかasync-awaitを使用します。
カスタムのエラー処理や文字列によるエラー処理は複雑さを招くため、常に組み込みのerrorオブジェクトを使ってシンプルにします。
ミドルウェアでエラーを処理すると、コードが重複する可能性があります。エラー処理のロジックは一元的に管理するのが最適です。
エラー処理のフローを定期的にテストし、誤検知や検出漏れが起きないことを確認します。
原因不明のエラーが発生した際に再起動するよう、プロセス管理ツールを使用します。Node.jsのプロセス管理ツールには、Pm2やforeverなどがあります。
5. 不要な情報を送信しない
フロントエンドに情報を送信する際は、必要なデータだけを送るようにしてください。理論上は、表示する情報を自由にフィルタリングできますが、攻撃者はバックエンドから非表示のデータにアクセスできる可能性があります。機密データへのアクセスを確実に防ぐには、絶対に必要な場合を除き、そもそも送信しないことが唯一の方法です。
6. リクエストサイズを制限する
Node.jsのリクエストサイズのデフォルト上限は5MBです。ハッカーがサーバーに大量のリクエストを送りつけるDDoS攻撃を防ぐには、Node.jsで許可するリクエストサイズをさらに制限できます。
簡単に実施できる方法を2つご紹介します。
body-parserパッケージの「limit」オプションを設定し、小さなペイロードのみを受け付けます。
リバースプロキシまたはExpressのミドルウェアを使い、特定の種類のコンテンツにサイズ制限を設定します。
7. ユーザー入力を検証する
悪意のある攻撃者がXSS攻撃を成功させられる理由の一つは、ユーザー入力が検証されていないことです。まず、DOMPurifyなどのNPMパッケージを使ってユーザー入力をサニタイズします。その後、express-validatorやXSS-filtersなどのフォーム検証ライブラリを使います。フォーム検証ライブラリを使うと、各リクエストの各入力を検証する単調な作業を自動化できます。XSS-filtersのようなコンテキスト依存の出力フィルターは開発者にとって使いやすく、XSS攻撃を防ぐために必要最小限の文字をエンコードします。
8. 安全なデシリアライズを徹底する
Node.jsには、高度なオブジェクトのシリアライズ機能がありません。そのため攻撃者は、シリアライズされたオブジェクトを使ってペイロードを転送できます。このような事態を避けるため、整合性とユーザー認証のチェックを実施し、デシリアライズしたデータをサニタイズしてください。より細かな対策として、CSRF対策トークン、カスタムリクエストヘッダー、CookieセッションのSameSiteフラグ、ユーザーの操作に基づく保護を使用します。
9. セキュリティリンターとSASTツールを使用する
攻撃につながる脆弱性を修正するには、まず脆弱性の場所を把握する必要があります。リンタープラグインや静的アプリケーションセキュリティテスト(SAST)などのツールを使うと、このプロセスを自動化し、見落としを防げます。
eslint-plugin-node-securityなどのリンターは、ソースコードを分析して、安全ではないプラクティスを特定し、通知します。Snyk CodeなどのSASTツールは、Node.jsのコードを記述中に監視し、潜在的な脆弱性を通知します。
10. Node.jsをroot以外のユーザーとして実行する
これはあらゆる場面で推奨されるプラクティスですが、Node.jsでは特に、rootユーザーとして実行しないことが重要です。root以外のユーザーとしてNode.jsを実行すれば、悪意のある攻撃者に悪用される可能性のある攻撃対象領域を制限できます。
この推奨事項は最小権限の原則に沿ったものです。ユーザーには、業務に必要な分だけのアクセス権を付与します。root権限を付与するのは、ごく限られた状況に限るべきです。
SnykがNode.jsのセキュリティに貢献
2021年5月以降、SnykはNode.jsエコシステムの脆弱性開示プログラムを引き継ぎ、セキュリティ向上に貢献しています。Snykの専門チームであるセキュリティアナリストと研究者が、Node.jsの脆弱性開示レポートをトリアージして検証し、報告されたパッケージのメンテナーに連絡して、Snykの脆弱性開示ポリシーに沿った責任ある開示プロセスを開始します。
さらに、Snyk製品を使えば、5分で脆弱性を見つけて修正できます。SnykがNode.jsのセキュリティをどのように高めるかをご紹介します。
Snyk Open Sourceは、Node.jsアプリケーションの依存関係にある脆弱性を特定し、開発者に通知します。これにより、今回ご紹介した重大なセキュリティリスクからコードを保護できます。
Snyk Codeは、アプリケーションコードに潜む脆弱性を特定し、開発者に通知するSASTツールです。
Snyk Containerは、SDLC全体を通じて、コンテナやKubernetesワークロードの脆弱性を開発者が発見できるよう支援します。
Node.jsをコンテナで使用している場合は、DockerでNode.jsアプリケーションをコンテナ化するための追加のベストプラクティスもご覧ください。
JavaScriptのセキュリティを守るSnyk
最初のコードから最後のnpm依存関係まで、SnykはIDE、CLI、GitのワークフローからJavaScriptアプリケーションを安全に保ちます。
Node.jsセキュリティに関するよくある質問
Node.jsは安全ですか?
Node.jsプラットフォーム自体は安全ですが、パッケージ管理システム(npm)を通じてサードパーティ製のオープンソースパッケージを利用するため、サイバー攻撃の危険にさらされる可能性があります。Node.jsのセキュリティを維持するには、企業はこの記事で紹介するようなベストプラクティスを実施する必要があります。
Node.jsを安全に保つにはどうすればよいですか?
ユーザー入力の検証、認証の実装、リクエストサイズの制限、ログ記録と監視の設定などの対策は、Node.jsのセキュリティを確保するための第一歩です。コードインジェクション攻撃への具体的な対策については、Node.jsでコードインジェクションを防ぐ5つの方法をご覧ください。
Node.jsはハッキングされる可能性がありますか?
ハッカーは、本番サーバーへの大量のリクエスト送信、悪意のあるJavaScriptの挿入、プログラムへの処理に時間のかかる入力の送信などによって、Node.jsアプリケーションに侵入する可能性があります。また、NPMはオープンソースであるため、Node.jsは脆弱性のリスクにもさらされます。