説明
ファイル名を使って存在やアクセス可否を調べた後、同じパスを開き直したり書き込んだりすると、その間に攻撃者がファイルを置き換える可能性があります。特に一時ディレクトリや共有ディレクトリでは、シンボリックリンクや先回りしたファイル作成によって、意図しないファイルを上書きするおそれがあります。
想定される影響
- 検査後のパスをシンボリックリンクに置き換えられ、機密ファイルを上書きする可能性があります。
- 存在の確認から作成までの間に、別のプロセスがファイルを作成する可能性があります。
- 読み取り前の検査結果と使用時の状態が異なり、情報漏えいや認可の回避につながるおそれがあります。
対処方法
- 同じファイル名を再検査せず、ファイルディスクリプターを使う API を利用してください。
- 新規ファイルは
O_CREAT | O_EXCLなどのフラグでアトミックに作成してください。 - 一時ファイルは専用 API を使い、非公開のディレクトリ内で作成してください。
例
変更前
javascript
const fs = require("fs");
const os = require("os");
const path = require("path");
const targetPath = path.join(os.tmpdir(), "report.txt");
if (!fs.existsSync(targetPath)) {
fs.writeFileSync(targetPath, "report");
}
変更後
javascript
const fs = require("fs");
const os = require("os");
const path = require("path");
const targetPath = path.join(os.tmpdir(), "report.txt");
const fd = fs.openSync(
targetPath,
fs.constants.O_CREAT | fs.constants.O_EXCL | fs.constants.O_WRONLY,
0o600,
);
try {
fs.writeFileSync(fd, "report");
} finally {
fs.closeSync(fd);
}
説明:
- 変更前:
existsSyncの検査からwriteFileSyncの呼び出しまでに、対象パスが変わる可能性があります。 - 変更後: アトミックな作成フラグによって、検査と作成を一つのファイルシステム操作で行います。既存のパスでは失敗するため、呼び出し元でエラーを処理する必要があります。