경로 조작 (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