설명
사용자 입력을 파일 경로로 직접 사용하면 공격자가 ../ 같은 경로 요소를 이용해 허용된 디렉터리 밖의 파일을 읽거나 수정할 수 있습니다.
잠재적 영향
- 민감 파일 읽기
- 임의 파일 삭제 또는 덮어쓰기
- 앱 샌드박스 내 데이터 노출
해결 방법
- 사용자 입력을 파일 경로로 직접 사용하지 않습니다.
- 기준 디렉터리와 결합한 뒤 표준화하고 결과가 기준 디렉터리 안에 있는지 확인합니다.
- 파일명은 허용 문자와 허용 확장자 목록으로 제한합니다.
예시
변경 전
swift
let fileName = readLine()!
let contents = try String(contentsOfFile: fileName)
변경 후
swift
import Foundation
enum PathValidationError: Error {
case invalidFileName
case outsideBaseDirectory
}
func readUpload(fileName: String, baseDirectory: URL) throws -> String {
guard !fileName.isEmpty,
fileName == URL(fileURLWithPath: fileName).lastPathComponent else {
throw PathValidationError.invalidFileName
}
// baseDirectory는 앱만 쓸 수 있는 디렉터리여야 합니다.
let base = baseDirectory
.resolvingSymlinksInPath()
.standardizedFileURL
let candidate = base
.appendingPathComponent(fileName, isDirectory: false)
.resolvingSymlinksInPath()
.standardizedFileURL
guard candidate.deletingLastPathComponent() == base else {
throw PathValidationError.outsideBaseDirectory
}
return try String(contentsOf: candidate, encoding: .utf8)
}
설명:
- 변경 전: 사용자 입력이 파일 경로 전체로 사용됩니다.
- 변경 후: 단일 파일명만 허용하고 기준 디렉터리와 후보 경로의 심볼릭 링크를 해석한 뒤, 실제 부모 디렉터리가 기준 디렉터리와 같은 경우에만 읽습니다. 예시처럼 기준 디렉터리는 앱만 수정할 수 있어야 하며, 공격자가 검사 후 경로를 교체할 수 없도록 보호해야 합니다.