ネットワークから受信したデータのローカルファイル保存

ネットワークから受信したデータのローカルファイル保存

説明

外部ネットワークの応答を検証せずにローカルファイルへ保存すると、任意のファイルのアップロードや信頼境界の越境につながるおそれがあります。そのファイルを後で信頼して実行、解析、公開すると、攻撃者がサーバーのファイルシステムに悪意のあるスクリプトや改ざんデータを持ち込む可能性があります。

想定される影響

  • 攻撃者が制御するファイルがサーバーに保存され、悪意のあるコード、スクリプト、改ざんデータが配布される可能性があります。
  • 公開ディレクトリや実行可能な場所への保存が、後続の攻撃につながるおそれがあります。
  • 大きな応答の保存により、ディスク容量の枯渇やサービス拒否が発生する可能性があります。

対処方法

  • 保存前に応答の取得元、コンテンツタイプ、サイズ、拡張子、ファイルのマジックバイトを検証してください。
  • 保存先は専用の隔離ディレクトリに限定し、実行可能なパスや公開パスへ直接書き込まないでください。
  • 必要に応じてマルウェア検査、ダウンロード先の許可リスト、信頼するキーによる署名検証を追加してください。

例

変更前

javascript
const fs = require("fs");
const axios = require("axios");

async function download(url) {
  const response = await axios.get(url);
  fs.writeFileSync("/var/www/public/file.bin", response.data);
}

変更後

validateDownload と verifySignature はアプリケーション固有の検証関数で、実装は省略しています。検証基準と信頼する署名キーを定め、ダウンロードのサイズと時間も制限してください。保存先ディレクトリは攻撃者が変更できないように保護する必要があります。

javascript
const fs = require("fs");
const axios = require("axios");

async function download(url) {
  const response = await axios.get(url, { responseType: "arraybuffer" });
  const payload = validateDownload(response.data, response.headers);
  await verifySignature(payload);
  fs.writeFileSync("/srv/app/downloads/file.bin", payload, { mode: 0o600 });
}

説明:

  • 変更前: 外部の応答を検証せず Web 公開パスへ保存するため、攻撃者が制御するファイルを公開する可能性があります。
  • 変更後: 内容と署名を検証してから隔離した場所へ書き込みます。mode: 0o600 は新規ファイル作成時の権限であり、既存ファイルの権限は変更しません。

参考資料