共有状態へのリクエストデータの保存

共有状態へのリクエストデータの保存

説明

リクエストやセッションのユーザー別データを、モジュールのグローバル変数やシングルトンへ保存すると、同じプロセスの別のリクエストからも参照できる状態になる可能性があります。

マルチスレッドでの実行は前提ではありません。プロセスがリクエストを順番に処理しても、ユーザー別の値が共有状態に残ることがあります。

想定される影響

  • 前のユーザーの識別子や権限情報が、別のユーザーへ漏れるおそれがあります。
  • 別のユーザーの状態を使って、誤った認可判断が行われる可能性があります。

対処方法

  • リクエスト固有のデータは、ローカル変数、リクエストオブジェクト、セッションストアなど、リクエストごとの範囲を分離できる場所に保存してください。
  • ユーザー別の認証情報、セッション、個人情報を、モジュールのグローバル変数やシングルトンへ保存しないでください。

例

変更前

javascript
let currentUser;

app.get("/profile", (req, res) => {
  currentUser = req.session.user;
  res.json(currentUser);
});

変更後

javascript
app.get("/profile", (req, res) => {
  const currentUser = req.session.user;
  res.json(currentUser);
});

解説:

  • 変更前: ユーザーの値がグローバル変数に残り、別のコードや後続のリクエストから参照できます。表示した同期ハンドラー自体は、代入した直後に同じ値を返しますが、共有状態の再利用や非同期処理の割り込みによって、別のユーザーの値が混ざる危険があります。
  • 変更後: このリクエストの関数内のローカル変数だけを使います。セッションミドルウェアと認証は事前に構成しておく必要があります。

参考資料