경로 조작 (Path Traversal)

Path Traversal

설명

경로 조작은 사용자 입력을 그대로 파일 경로에 사용할 때 발생합니다. 공격자는 ../, 절대 경로(/, C:\ 등), 또는 심볼릭 링크를 이용해 애플리케이션이 의도한 디렉터리 밖의 파일에 접근하도록 유도할 수 있습니다. 이를 통해 /etc/passwd 같은 시스템 파일을 읽거나, 애플리케이션 설정/로그를 덮어쓰고 삭제할 수 있습니다.

잠재적 영향

  • Sensitive Data Exposure (민감 정보 노출): 디렉터리 밖의 시스템 파일, 소스 코드, 환경설정(.env 등) 유출

  • Data Tampering/Deletion (데이터 변경/삭제): 업로드/로그/설정 파일을 덮어쓰기 또는 삭제하여 기능 오작동 유발

  • Privilege Escalation (권한 상승): 서비스 권한으로 임의 파일 쓰기를 악용해 실행 경로에 스크립트 배치 등 간접적 권한 상승 가능

  • Service Disruption (서비스 중단): 핵심 파일 삭제/손상으로 애플리케이션 장애 또는 DoS 유발

해결 방법

  • 사용자 입력으로 경로를 만들지 말고, 반드시 정규화와 경계 확인을 수행합니다.

    • const resolved = fs.realpathSync(path.resolve(SAFE_ROOT, input));

    • resolved가 SAFE_ROOT + path.sep로 시작하는지 확인합니다. 아니라면 거부합니다.

  • 단순 파일명만 허용해야 한다면 allow-list(확장자/패턴) 또는 sanitize-filename 사용, 혹은 엄격한 정규식(예: ^[a-zA-Z0-9._-]{1,100}$) 검증을 적용합니다.

  • 절대 경로, .., 빈 값 등은 즉시 차단합니다.

  • 심볼릭 링크 우회를 막기 위해 realpath로 링크를 해소하고, 필요 시 fs.lstat로 링크 사용 자체를 금지합니다.

  • 파일 접근 권한을 최소화하고(Least Privilege), 에러 메시지에는 실제 경로를 노출하지 않습니다.

  • 업로드/다운로드 루트를 고정(SAFE_ROOT)하고, 그 밖의 경로 접근은 금지합니다.

취약한 코드 및 안전한 코드 예시

취약한 코드

안전한 코드

설명:

  • 취약한 코드: 사용자 입력 f를 검증 없이 경로 결합(join)만 한 뒤 파일을 읽습니다. path.join은 ..를 제거하지 못해 상위 디렉터리로 탈출이 가능하며, 결과적으로 애플리케이션 루트 밖의 임의 파일에 접근할 수 있습니다.

  • 안전한 코드: SAFE_ROOT를 기준으로 path.resolve로 정규화하고, fs.realpathSync로 심볼릭 링크를 해소한 다음, 결과 경로가 SAFE_ROOT 하위인지 접두어 비교로 확인합니다. 이 경계 확인을 통과한 경로만 파일 접근에 사용함으로써 디렉터리 트래버설을 차단합니다.

참조

Last updated