Node.jsのHTTPサーバーはHostヘッダー由来の例外でプロセスごと落ちうる
Node.js
セキュリティ
HTTP
問題
Node.js の HTTP サーバー生成関数に渡すリクエストハンドラを async で書き、先頭付近で Host ヘッダーの値からリクエスト URL を組み立てると(URL コンストラクタにパスとホスト由来の base を渡すパターン)、空白や制御文字を含む不正な Host で URL コンストラクタが TypeError を投げる。これが async ハンドラ内の未捕捉例外だと「未処理の Promise リジェクション」になり、Node 15 以降の既定の挙動(unhandled-rejections=throw)ではプロセスが終了する。
結果として、認証不要・1 リクエスト(不正な Host ヘッダーを1つ付けるだけ)でサーバープロセスを落とせる。ループされれば継続的なサービス停止になる。
判断基準と対策
- リクエストハンドラ本体は必ず try/catch で包み、パース失敗は 400 等で返す。URL コンストラクタなど例外を投げうる処理を catch の外に置かない。
- 多層防御としてプロセスレベルの unhandledRejection / uncaughtException ハンドラを登録し、ログ出力のみでプロセスを落とさない。
- ユーザー制御の値(Host、パス、ヘッダー)を URL コンストラクタやパーサに渡す箇所は、事前に妥当性を検証するか、安全なデフォルトにフォールバックする。
適用場面
生の node の http / https モジュールでサーバーを書く場合や、フレームワークを介さずリクエストを処理する MCP サーバー・プロキシ・ヘルスチェック層などに当てはまる。Express 等の多くは内部で例外を捕捉するが、独自ハンドラを挟むと同じ穴が空きうる。
検証方法
サーバーを起動し、生ソケットで不正な Host(空白入り・空文字・制御文字入り)を送る。修正前は同入力でプロセスが終了し、修正後は 4xx などの応答を返しプロセスが生存し続けることを確認する。