안전하지 않은 임시 파일 생성

Insecure Temporary File

설명

운영체제의 공용 임시 디렉터리(os.tmpdir())에 예측 가능한 파일명을 직접 만들어 쓰기/열기하면 다른 사용자(또는 컨테이너/프로세스)와 충돌하거나, 공격자가 미리 심볼릭 링크(symlink)·하드링크를 심어두는 레이스 컨디션이 발생할 수 있습니다. 이로 인해 민감 정보가 노출되거나, 공격자가 의도한 위치로 파일이 생성/덮어쓰기 되어 권한 상승 또는 원격 코드 실행으로 이어질 수 있습니다. 공격 시나리오 예: 공격자가 /tmp/report.txt를 중요한 시스템 파일로 향하는 symlink로 미리 만들어 두고, 애플리케이션이 그 경로에 쓰기를 수행하면 시스템 설정 파일을 덮어쓰게 됩니다.

잠재적 영향

  • 정보 노출: 공용 임시 디렉터리에 생성된 파일이 다른 사용자에게 읽히거나, 로그/토큰/민감 데이터가 유출될 수 있습니다.
  • 파일 덮어쓰기/무결성 훼손: 공격자가 미리만든 symlink를 통해 중요한 파일(예: 설정, 키 파일)을 덮어쓰게 할 수 있습니다.
  • 권한 상승/원격 코드 실행: 덮어쓴 파일이 실행·로드되는 경로일 경우, 악성 내용 주입으로 코드 실행이 가능해질 수 있습니다.
  • 서비스 장애(DoS): 이름 충돌·접근 권한 문제로 예외가 발생하여 임시 작업이 실패하거나 서비스가 중단될 수 있습니다.

해결 방법

  • 검증된 라이브러리 사용: tmp 같은 라이브러리로 안전한 임시 파일·디렉터리를 생성하세요.
  • 고유 임시 디렉터리 생성: fs.mkdtemp(또는 mkdtempSync)으로 os.tmpdir() 하위에 예측 불가능한 전용 디렉터리를 먼저 만든 뒤 그 안에서 작업하세요.
  • 안전 플래그/권한 사용: 파일 생성 시 flag 'wx'('ax')로 존재 시 실패하도록 하고, mode 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 }); 로 정리
}

설명:

  • 변경 전: os.tmpdir() 하위에 고정된 파일명(report.txt)으로 바로 쓰기를 수행하면 다른 사용자가 미리 같은 이름의 파일이나 symlink를 만들어 두는 레이스 컨디션이 발생합니다. 또한 기본 권한으로 생성되어 불필요하게 넓은 접근권을 줄 수 있어 정보 노출·파일 덮어쓰기·권한 상승 위험이 있습니다.
  • 변경 후: 먼저 fs.mkdtemp로 예측 불가능한 전용 임시 디렉터리를 만들고, 그 내부에서만 작업하여 외부 사용자가 개입하기 어렵게 했습니다. 파일 생성 시 flag 'wx'로 기존 경로를 덮어쓰지 않고 실패하게 하며, mode 0o600으로 접근을 제한합니다. 전용 디렉터리를 다른 사용자가 변경할 수 없도록 보호하고, 사용 후 정리하세요.

참조