OpenNext Cloudflare: キャッシュインターセプトにより、エンコードされたパスに対するミドルウェアの保護を回避できる場合があります。
## 概要
キャッシュインターセプトが有効になっている場合、`@opennextjs/cloudflare`は、ミドルウェアのマッチングとキャッシュの参照中に、パーセントエンコードされたパスを異なる解釈で処理する可能性があります。
エンコードされたリクエストが認証ミドルウェアと一致しない場合、それが保護されたルートのキャッシュキーにデコードされ、その結果、ミドルウェアが呼び出されずにキャッシュされた応答が返される可能性があります。
`enableCacheInterception`はデフォルトで無効になっています。
## 影響
認証されていない攻撃者が、ミドルウェアによって保護されるように意図されたルートからキャッシュされたコンテンツを取得する可能性があります。
アプリケーションが以下の条件を満たす場合に影響を受けます。
- 明示的に`enableCacheInterception`を有効にする。
- アクセス制御にミドルウェアに依存する。
- 一致するキャッシュされたルートが存在する。
## 詳細
以前は、ミドルウェアのマッチングでエンコードされたリクエストのパス名を使用していましたが、キャッシュインターセプトでは、キャッシュエントリを選択する前にパス名をデコードしていました。
例えば、以下のようなアプリケーションを考えてみましょう。
- ミドルウェアのマッチャー: `/admin/:path*`
- `/admin`に対して`401 Authentication required`を返すミドルウェア
- 静的に生成され、キャッシュされた`/admin`ルート
- キャッシュインターセプトが有効になっている:
```ts
export default defineCloudflareConfig({
incrementalCache: staticAssetsIncrementalCache,
enableCacheInterception: true,
});
```
攻撃者は、以下のようなリクエストを送信できます。
```http
GET /%61dmin
```
エンコードされたパス名は`/admin/:path*`と一致しないため、認証ミドルウェアは呼び出されません。キャッシュインターセプトは、`%61dmin`を`admin`にデコードし、キャッシュされた`/admin`の応答を返す可能性があります。
```http
HTTP/1.1 200 OK
x-opennext-cache: HIT
保護されたコンテンツ
```
不正なパス名によって、さらに不整合が生じる可能性があります。例えば:
```http
GET /%61dmin/%ZZ
```
以前の実装では、各セグメントを個別にデコードしていました。`%61dmin`を`admin`にデコードしましたが、不正な`%ZZ`セグメントは保持され、部分的にデコードされたパス名を使用してキャッシュの参照を続行することができました。
## 修正
この修正により、ミドルウェアのマッチングとキャッシュの参照におけるエンコードされたパスの処理が統一され、不正なパスは部分的にデコードするのではなく、拒否されるようになります。詳細については、[opennextjs-aws#1199](https://github.com/opennextjs/opennextjs-aws/pull/1199) および [opennextjs-aws#1200](https://github.com/opennextjs/opennextjs-aws/pull/1200) の関連する修正を参照してください。
ユーザーは、`@opennextjs/cloudflare` を `1.20.2` 以降のバージョンにアップデートする必要があります。
## 応急処置
アプリケーションのアップデートがすぐにできない場合:
1. `enableCacheInterception: true` を削除して、キャッシュのインターセプトを無効にします。
2. 保護されたルートハンドラ内で認証を強制し、ミドルウェアだけに依存しないようにします。
3. 保護されたルートに対して、Worker に到達する前に、信頼できるプロキシでエンコードされたパスを拒否します。
個々のエンコードされたマッチングのバリエーションを追加することは、完全な解決策ではありません。なぜなら、パス名には複数の同等のエンコードが存在する可能性があるからです。
影響を受けるパッケージ:
- npm (JavaScript) `@opennextjs/cloudflare`: 影響範囲は `0.3.0` 以上、`1.20.2` 未満のバージョンで、`1.20.2` で修正されています。