説明
os.tmpdir() などの共有一時ディレクトリで、予測できる名前のファイルに直接書き込むと、別のプロセスやユーザーの操作と競合する場合があります。攻撃者が先にシンボリックリンクなどを作成し、書き込み先を変更させるおそれがあります。アプリケーションの権限や対象ファイルの用途によっては、情報漏えい、ファイルの上書き、権限昇格、コード実行につながります。たとえば、先に作られた /tmp/report.txt のリンクが、重要なシステムファイルを指している場合があります。
想定される影響
- 一時的なログ、トークン、機密データを他のユーザーに読み取られるおそれがあります。
- 先に作成されたシンボリックリンクを通じて、設定やキーファイルなどを上書きされる可能性があります。
- 改ざんされたファイルが後で実行・読み込みされると、コード実行や権限昇格につながる場合があります。
- 名前の衝突や権限エラーで、一時処理やサービスが停止するおそれがあります。
対処方法
tmpなどの検証されたライブラリを使用してください。fs.mkdtempまたはmkdtempSyncでos.tmpdir()配下に専用ディレクトリを作り、その中で処理してください。'wx'、'ax'などの排他的な作成フラグと、0o600などの制限した権限を使用してください。os.tmpdir()から組み立てた予測可能なパスを、そのままfs.writeFile(Sync)やfs.createWriteStreamに渡さないでください。- 使用後はファイルとディレクトリを削除し、必要に応じて所有者や権限を確認してください。
- トークンや秘密キーには、一時ファイルより安全なシークレットストアを優先してください。
例
変更前
javascript
const fs = require("fs");
const os = require("os");
const path = require("path");
function saveReport(data) {
// 変更前: 共有 TMP 内の予測可能な名前に直接書き込む
const p = path.join(os.tmpdir(), "report.txt");
fs.writeFileSync(p, data); // 既定の権限とフラグにより、競合や過剰なアクセスの可能性
return p;
}
変更後
javascript
const fs = require("fs");
const os = require("os");
const path = require("path");
const crypto = require("crypto");
function saveReportSafely(data) {
// 1) 接頭辞にランダムな接尾辞を付けて一意の一時ディレクトリを作成
const base = path.join(os.tmpdir(), "myapp-");
const tmpDir = fs.mkdtempSync(base); // 例: /tmp/myapp-abc123
// 2) ディレクトリ内で、衝突を避けるランダムなファイル名を使用
const name = "report-" + crypto.randomBytes(8).toString("hex") + ".log";
const filePath = path.join(tmpDir, name);
// 3) 既存のパスなら失敗させ、最小限の権限で作成
fs.writeFileSync(filePath, data, { flag: "wx", mode: 0o600 });
return filePath;
// 使用後、必要に応じて fs.rmSync(tmpDir, { recursive: true, force: true }); で削除
}
説明:
- 変更前: 書き込み前に、他のユーザーが
report.txtやシンボリックリンクを作成できます。既定の権限が広すぎる場合もあり、情報漏えいや上書きの危険が生じます。 - 変更後:
fs.mkdtempで一意の専用ディレクトリを作成します。'wx'は既存のパスを上書きせずに失敗し、0o600はアクセスを制限します。他のユーザーがディレクトリを変更できないようにし、使用後は削除してください。