728x90
구글 플레이 스토어에 앱을 업데이트하는 중 다음과 같은 경고가 표시되기 시작했다.
해당 경고가 가리키는 코드를 확인해 보니 압축 파일 처리에 대한 함수였다.
fun unZip(zipFile: File, destFolder: File): List<File> {
val result = ArrayList<File>()
ZipFile(zipFile).use { zip ->
zip.entries().asSequence().forEach { entry ->
if (entry.isDirectory) {
File(destFolder, entry.name).mkdirs()
} else {
zip.getInputStream(entry).use { input ->
val file = File(destFolder, entry.name)
file.outputStream().use { output ->
input.copyTo(output)
}
result.add(file)
}
}
}
}
return result
}
이 로직에서 구글의 보안 정책을 위반하는 모양이다.
압축 파일 경로 순회에 대한 처리 내용을 아래 문서에서 확인할 수 있었다.
https://developer.android.com/topic/security/risks/zip-path-traversal?hl=ko
문서를 확인해본 결과, 기존 로직에서 누락된 몇 가지 과정들이 있었다.
1. 각 항목을 추출하기 전에 타깃 경로가 대상 디렉토리의 하위 요소인지 항상 확인해야 한다. 안전하지 않은 경우 앱이 씸볼릭 링크 공격과 같은 다른 취약점에 노출되기 쉽기 때문이다.
2. 대상 디렉토리가 비어있는지, 검사해야 한다. 검사하지 않으면 앱이 비정상 종료되거나 손상될 수 있다.
아래와 같이 로직이 수정되고 나서 더 이상 경고가 표시되지 않았다.
@Throws(IOException::class)
fun unZip(zipFile: File, destFolder: File): List<File> {
val result = ArrayList<File>()
if (!destFolder.isDirectory) { //디렉토리 유효성 검사
throw IOException("Destination is not a directory.")
}
val files = destFolder.list()
if (files != null && files.isNotEmpty()) { //폴더 비어있는지 검사
throw IOException("Destination directory is not empty.")
}
ZipFile(zipFile).use { zip ->
zip.entries().asSequence().forEach { entry ->
if (entry.isDirectory) {
val file = File(destFolder, entry.name)
ensureZipPathSafety(file, destFolder)
file.mkdirs()
} else {
zip.getInputStream(entry).use { input ->
val file = File(destFolder, entry.name)
ensureZipPathSafety(file, destFolder)
file.outputStream().use { output ->
input.copyTo(output)
}
result.add(file)
}
}
}
}
return result
}
//대상 디렉터리의 하위 요소인지 확인
@Throws(Exception::class)
private fun ensureZipPathSafety(outputFile: File, destDirectory: File) {
val destDirCanonicalPath = destDirectory.canonicalPath
val outputFileCanonicalPath = outputFile.canonicalPath
if (!outputFileCanonicalPath.startsWith(destDirCanonicalPath))
throw ZipException("Illegal File Path: $outputFileCanonicalPath")
}
728x90