Skip to main content

Node.jsのWebフレームワークを比較:最も安全なのはどれ?

prioritize the security backlog

2023年3月8日

0 分で読めます

JavaScriptは世界で最も人気のあるプログラミング言語であり、開発者が安全で信頼性の高いNode.jsのWebアプリケーションを構築するのに役立つ、多数のWebフレームワークを提供しています。各フレームワークには独自の機能があり、どのフレームワークが適しているかは、好みや作成するアプリケーションの種類によって異なります。 

利用できるフレームワークが数多くある中で、それぞれのセキュリティを評価する方法が必要です。この記事では、人気の高い3つのフレームワーク、Express.js、NestJS、Fastifyを取り上げ、Node.jsのセキュリティに関するベストプラクティスへの準拠度を評価します。

Node.jsのWebフレームワークのセキュリティを比較

JavaScriptベースのWebフレームワークはすべて、Node.jsランタイム上に構築されています。npmエコシステムを利用するアプリケーションでは、通常、機能を追加するために複数のnpm依存関係を組み合わせます。そのため、どのフレームワークを使う場合でも、Node.jsの脆弱性やnpmの依存関係がアプリケーションに影響する可能性があります。アプリケーションのセキュリティは、開発時にベストプラクティスと設計原則を採用するかどうかに左右されます。

Webフレームワークを使うと、最新のパッケージを利用し、定期的にアップデートしやすくなります。また、アプリケーションへの不正アクセスの可能性を低減する抽象化レイヤーも提供します。こうした理由から、アプリケーションの作成にはWebフレームワークを使うべきです。 

以下では、3つのNode.jsフレームワークのセキュリティ機能について説明し、比較します。

Express.js

Express.jsは、MERNスタックやMEANスタックを使ったWebアプリケーションやAPIの構築を目的とする、高速で軽量なNode.js用Webフレームワークです。このフレームワークでは、本番環境にアプリケーションをデプロイする前に、数多くのセキュリティのベストプラクティスに従うことが推奨されています。また、Express.jsはNode.jsのセキュリティに関するベストプラクティスに従い、それに準拠するための推奨事項を数多く提示しています。

ブルートフォース攻撃を防ぐ 

Node.jsのベストプラクティス6.12では、認証メカニズムに対するブルートフォース攻撃の防止を扱っています。このプラクティスでは、/adminや/loginなどの機密性の高いルートでログイン試行回数を制限し、パスワードの総当たり攻撃や辞書攻撃のリスクを軽減する方法が推奨されています。rate-limiter-flexible npmパッケージを使い、リクエスト元のIPアドレスや、ユーザー名・メールアドレスなどリクエスト本文のパラメーターに基づいてログイン試行を制限できます。これらの情報を使って、連続した失敗回数を数えて制限するリミッターを設定できます。さらに、失敗回数が上限に達したIPアドレスを一定期間ブロックする別のリミッターも追加できます。Express.jsは、同じnpmパッケージの使用と、同様の指標に基づく認証試行のブロックを推奨しています。

正規表現の安全性を確保する 

Node.jsのベストプラクティス6.16では、脆弱なパターンを検出するために、validator.jsやsafe-regexなどのサードパーティ製正規表現検証パッケージの使用が推奨されています。独自の正規表現パターンを実装することは推奨されていません。正規表現の記述が不適切だと、正規表現DoS攻撃の影響を受けやすく、イベントループを完全にブロックされるおそれがあります。

HTTPヘッダーを適切に設定する 

ベストプラクティス6.6では、クロスサイトスクリプティング、Cookieのハイジャック、クリックジャッキングなどの脆弱性からアプリケーションを保護するために、安全なヘッダーを使用することが推奨されています。以前、Express.jsではforwardedモジュールにセキュリティ上の脆弱性が見つかりました。このモジュールはX-Forwarded-Forヘッダーを処理します。この脆弱性を悪用するために、攻撃者はクエリを細工し、解析時に必要なイベントループをブロックしてサービス拒否を引き起こすことができました。こうした脆弱性や類似の脆弱性を防ぐため、Express.jsではHelmetを使ってセキュリティ関連のヘッダーを簡単に設定し、Node.jsのベストプラクティスに準拠できます。 

NestJS

NestJSは、フロントエンドフレームワークのAngularから強い影響を受けたWebアプリケーションフレームワークです。スケーラブルなバックエンドアプリケーションの構築を目的としています。FastifyまたはExpressをラップするNestJSのセキュリティは、基本的にそれらのフレームワークと同等です。NestJSの主な利点は、アプリケーション開発に活用できるアーキテクチャと構造設計を備えていることです。

NestJSはTypeScriptを基盤としてサポートしているため、保守性の高い複雑なアプリケーションを作成できます。また、特定のリクエストをルートハンドラーで処理するかどうかを判断できるGuardsも備えています。

クライアント側からGuardを経由してRoute HandlerへHTTPリクエストが流れる様子を示すフロー図

このフレームワークは、さまざまな方法でNode.jsのセキュリティに関するベストプラクティスに準拠しています。

暗号化とハッシュ化 

ベストプラクティス6.8では、パスワードなどの機密性の高いユーザーデータを平文で保存せず、ハッシュ化することが推奨されています。このプラクティスでは最低限使用すべき3つの関数を挙げていますが、攻撃者にハッシュ方式を知られた場合の被害を軽減するために、より高度なパラメーターやプログラムごとに固有の組み合わせを使うことも推奨しています。また、パスワードをハッシュ化する前にソルトを追加することも推奨されています。NestJSは、情報の暗号化とハッシュ化を推奨し、このプラクティスに従っています。暗号化には、組み込みのcryptoモジュールの使用が推奨されています。ハッシュ化には、bcryptまたはargon2パッケージの使用が推奨されています。

受信リクエストを検証する

Node.jsのベストプラクティス6.10では、受信リクエストの本文を検証することが推奨されています。つまり、アプリが受け入れるペイロードを定義し、それ以外のペイロードを受信したら速やかにエラーにします。攻撃者が構造、値、長さの異なるカスタムペイロードを送信できなくなるため、DDoS攻撃のリスク軽減につながります。NestJSでは、すぐに使える複数のパイプが用意されており、検証を実行できるため、このプラクティスを簡単に実装できます。

セッションミドルウェアの設定を変更する

Node.jsのベストプラクティス6.22では、セッションIDの特定やセッションハイジャックなどの攻撃を減らし、ユーザーとアプリケーションの保護を強化するため、Cookieのデフォルト設定を調整することが推奨されています。NestJSでは、セッション設定を変更する方法が用意されているため、このプラクティスを簡単に実装できます。このフレームワークに影響したセキュリティ脆弱性の例として、NestJSのプロキシモジュールである@finastra/nestjs-proxyモジュールの問題があります。このパッケージの影響を受けるバージョンでは、機密性の高いCookieがデフォルトで転送されることにより、情報が漏えいするおそれがありました。

Fastify

Fastifyは、高速かつ低オーバーヘッドを目指すNode.js用Webフレームワークです。HapiとExpressに着想を得ており、Webアプリケーションやサービスを構築するためのシンプルで安定した基盤として設計されています。最小限のコードベースとシンプルで宣言的な設定により、開発者はすばやくサーバーを立ち上げられます。 

このフレームワークでは、次のことを推奨し、Node.jsのセキュリティに関するベストプラクティスに従っています。

クライアントからのリクエストを制限するためのfastify/rate-limitの使用

これはベストプラクティス6.12に準拠しています。このプラクティスによると、レート制限は、/loginや/adminなどの高い権限を持つルートに対する認証のブルートフォース攻撃を防ぐのに役立ちます。レート制限は、こちらで説明されている2つの指標に基づいてリミッターを作成することで実現できます。

重要なセキュリティヘッダーを設定するためのfastify/helmetの使用

これはベストプラクティス6.6に準拠しています。セキュリティヘッダーを適切に設定することで、クロスサイトスクリプティング、クリックジャッキング、その他の攻撃からアプリケーションを保護できます。

コミュニティ提供のfastify-cockroachdbプラグインの使用

このプラグインを使うと、Sequelize ORM経由でCockroachDBのPostgreSQLインスタンスに接続できます。ベストプラクティス6.4によると、ORM/DRMライブラリは、JavaScriptの文字列連結やテンプレート文字列の使用を防ぐことで、SQL/NoSQLインジェクションの防止に役立ちます。どちらもアプリケーションをさまざまな攻撃にさらすおそれがあります。また、Sequelize、Knex、mongooseなど、インジェクション攻撃に対する保護機能が組み込まれた、信頼性の高いデータアクセスライブラリの使用も推奨されています。

同時リクエストを制限する

Node.jsのベストプラクティス6.2では、DoS攻撃の基本となる過剰な同時リクエストを防ぐため、レートリミッターの実装が推奨されています。このプラクティスでは、その目的に特化したサービスの利用が推奨されています。Fastifyには、この実現に役立つ@fastify/rate-limitプラグインが用意されています。

設定ファイルからシークレットを取り除く

Node.jsのベストプラクティス6.3では、鍵やシークレットを暗号化して保存するか、環境変数を使用することが推奨されています。平文で保存すると、発見されるおそれがあります。Fastifyは、設定ファイルの確認と読み込みができる@fastify/envプラグインを提供し、このプラクティスに従っています。ただし、シークレットを環境変数から読み込む方法は推奨されず、最終手段とすべきです。

このフレームワークのセキュリティ上の欠点の1つは、JSON Web Token(JWT)のブロックリストに対応していないことです。JWTをブロックリストに追加すると、攻撃者が期限切れや紛失したトークンを使って、トークンの所有者になりすますことを防げます。

このフレームワークで最近確認された脆弱性の例として、一部のバージョンに影響したDoS攻撃があります。

適切なフレームワークを選ぶ

この記事で取り上げたWebフレームワークはいずれも、十分な水準でセキュリティのベストプラクティスに準拠しています。ただし、NestJSはExpress.jsの抽象化レイヤーとして組み込みのセキュリティ機能を備えているため、Node.jsのセキュリティに関するベストプラクティスに最もよく準拠しています。その結果、攻撃者がシステムにアクセスしにくくなります。 

ここで紹介した各フレームワークには、それぞれの強みと最適な用途があります。また、それぞれに追加パッケージを統合して、安全で堅牢なアプリケーションを作成できます。

たとえば、Express.jsは最も人気があり、長い実績を持つフレームワークです。優れたドキュメントがあり、コミュニティのサポートも広く受けられます。

NestJSは、多数の組み込みパッケージを備え、Express.jsの抽象化レイヤーを提供し、TypeScriptをサポートしているため、スケーラブルなアプリケーションに適しています。一方Fastifyは、セキュリティを犠牲にすることなく、高速で効率的なWebアプリの構築に重点を置いています。

どのフレームワークを使う場合でも、開発者はWebアプリケーションの作成時に適切な依存関係を選択し、セキュリティのベストプラクティスに従う必要があります。また、既知の脆弱性をなくすために、パッケージを常に最新の状態に保つことも重要です。

Capture the Flagを始めよう

オンデマンドのバーチャル入門ワークショップを見て、Capture the Flagの課題の解き方を学びましょう。

続きを読む

blog feature snyk container custom base recommendations
Blog

Evo Agentic AppSecのご紹介:AI開発のスピードに対応するセキュリティ

AI駆動型開発のスピードに、従来のセキュリティワークフローは追いついていません。SnykのAgentic AppSecは、セキュリティエージェントが脆弱性を継続的に検出、修正、検証し、人が基準を定められるようにします。

feature insights context
Blog

自律型攻撃はすでに始まっている。防御もそのスピードに追いつかなければならない。

自律型攻撃者によって、防御に使える時間は短くなっています。継続的な検出、修復、検証、予防で、セキュリティチームが攻撃に歩調を合わせる方法をご紹介します。

illustration hero ai
Blog

AIハリケーンが到来

AIはソフトウェア開発とサイバー攻撃の双方を加速させています。リーダーは、エージェントとコードを開発の初期段階から保護し、実行時に制御を徹底するとともに、防御策を独立して検証しなければなりません。