ApostropheCMS: 認証されていないCSVインポートリクエストにより、拒否されたファイルがシステムの一時ディレクトリに残る

### 概要

拒否されたファイルが、オペレーティングシステムのテンポラリディレクトリに残る可能性があります。

Multerは、ファイル拡張子がチェックされる前にファイルを書き込みます。そして、拒否処理のパスでは、そのテンポラリファイルを削除しません。認証されていないユーザーが、この操作を大きなファイルで繰り返し行うことで、テンポラリディスクスペースを徐々に消費してしまう可能性があります。

### 詳細

該当のエンドポイントは以下の通りです。

```text
POST /api/v1/@apostrophecms/rich-text-widget/generate-csv-table
```

`packages/apostrophe/modules/@apostrophecms/rich-text-widget/lib/apiRoutes.js`において、Multerはまずファイルを`os.tmpdir()`に書き込みます。その後、ハンドラは拡張子が`csv`でないファイル名を拒否しますが、このエラー発生時の処理でMulterファイルが削除されることはありません。

このルートは、認証されたユーザーを必要としません。通常のCSRFクッキーで十分です。

テスト中、リクエストはHTTP 400エラー(「CSVファイルのみサポートされています」)を返し、その際、アップロードされたコンテンツ全体が、応答後に設定されたテンポラリディレクトリ内のランダムな名前のファイルとして残っていました。

### 以前の公開された作業との関連性

私は、Rich Text CSVのアップロードパスを`connect-multiparty`からMulterに移行した[PR #5013](https://github.com/apostrophecms/apostrophe/pull/5013)をレビューしました。このレポートは、その移行後のクリーンアップに関するものです。拒否されたMulterファイルがディスク上に残るという挙動は、PRやそのレビューでの議論には記載されていません。

### 実証

小さなテストファイルを作成します。より大きなファイルを使用すると、ディスクの使用量増加を実証できますが、1 MiBでローカルでの再現が可能です。

```bash
dd if=/dev/zero of=rejected.txt bs=1M count=1
```

通常のサイトのクッキーを取得し、拒否されたアップロードを送信します。

```bash
curl -c cookies.txt 'http://127.0.0.1:3000/' > /dev/null

curl -i -b cookies.txt \
-F 'file=@rejected.txt;filename=rejected.txt;type=text/plain' \
'http://127.0.0.1:3000/api/v1/@apostrophecms/rich-text-widget/generate-csv-table'
```

応答はHTTP 400エラーです。リクエスト前と後のシステムの一時ディレクトリの内容を比較してください。

```bash
ls -lt /tmp
```

ランダムに名前が付けられた新しいファイルが残り、アップロードされたデータが含まれています。

ログインは不要です。multipartリクエストを繰り返すと、追加の一時ファイルが作成されます。

### 影響

認証されていない攻撃者が、オペレーティングシステムの临时ディレクトリで使用されているパーティションを埋め尽くす可能性があります。そのパーティションがいっぱいになると、Apostropheや同じホスト上で動作している関連サービスが、ファイルのアップロードに失敗したり、一時データの作成に失敗したり、正常な動作を継続できなくなる可能性があります。

この攻撃には、繰り返しのHTTPリクエストのみが必要です。また、拒否された応答の後も、保存されたファイルは残ります。

影響を受けるパッケージ:
- npm (JavaScript) apostrophe: 4.33.0より前のバージョンに影響あり、4.33.0で修正済み。