許可範囲が広すぎる CORS の正規表現

ワイルドカードやエスケープしていないドットによる、許可範囲が広すぎる CORS の正規表現

説明

CORS(Cross-Origin Resource Sharing)で許可する出所を正規表現で指定するとき、ドット(.)をエスケープしないと、意図した範囲より多くのドメインを許可する場合があります。その結果、意図しない出所の JavaScript が応答を読み取れる可能性があります。機密情報が漏えいするかどうかは、応答の内容、認証情報の送信、サーバーの CORS 設定によって異なります。CORS はリクエストの送信自体をすべて防ぐ仕組みではありません。

想定される影響

  • 不適切な正規表現により、意図しない出所のスクリプトが応答を読み取れる可能性があります。
  • 攻撃者が悪意のあるドメインから個人情報や機密データにアクセスするおそれがあります。
  • 認証情報の送信が許可され、認証済みの応答に機密情報が含まれる場合、悪意のあるサイトからその情報を読み取られる可能性があります。

対処方法

  • ドメインを表す正規表現では、リテラルのドットを \. としてエスケープしてください。
  • 特定の信頼できる出所だけを許可する CORS ポリシーを設定してください。
  • ワイルドカード(*)や許可範囲が広すぎるパターンを避けてください。
  • 設定変更時にテストし、実際に許可される出所が意図した範囲内にあることを確認してください。

例

変更前

tsx
const corsDomains = [
  /(.+\.)*example.com$/,
  /^(http|https):\/\/.+\.evil\.com$/,
  /^(http|https):\/\/(.+)\.my\.site.com$/,
];

// CORS の設定例
app.use(cors({
  origin: corsDomains,
}));

変更後

tsx
const corsAllowedDomains = [
  /^https?:\/\/www\.example\.com$/,   // 'www.example.com' だけを許可
  /^https?:\/\/service\.my\.site\.com$/,  // サービス用サブドメインだけを許可
];

app.use(cors({
  origin: corsAllowedDomains,
}));

説明:

  • 変更前: 最初のパターンは、ドットがエスケープされておらず開始位置も固定していないため、似たホスト名まで許可する場合があります。他のパターンが許可する広いサブドメイン範囲も確認が必要です。
  • 変更後: 開始・終了位置とエスケープしたドットによって、二つのホストの HTTP または HTTPS の出所に限定します。本番環境での HTTPS の必要性と各出所の所有者も確認してください。

参考資料