Android 14(targetSdkVersion34)下ZipInputStream解压报错求助
问题原因及解决方案
原因
Android 14(对应targetSdkVersion 34)引入了强制的Zip路径安全校验机制,系统会自动拦截包含绝对路径(如以/开头)或../这类目录遍历字符的Zip条目,防止恶意Zip文件通过路径遍历攻击写入应用沙箱外的目录。而targetSdkVersion 33及更低版本没有这个强制校验逻辑,所以相同代码不会触发错误。
从错误栈里的Invalid zip entry path: /xxx可以明确看出,你的Zip文件中存在以/开头的绝对路径条目,被系统的SafeZipPathValidatorCallback拦截。
修复方案
在处理ZipEntry前,先对条目路径做安全预处理:
- 移除路径开头的
/,避免绝对路径 - 过滤包含
../的路径,防止目录遍历 - 确保处理后的路径是目标目录下的合法子路径
修改后的代码示例:
fun unzip( sourceFile: File, targetDirPath: String, onSuccess: (() -> Unit)?, onError: ((msg: String?) -> Unit)? ) { try { var sumLength: Long = 0 val zis = ZipInputStream( BufferedInputStream( FileInputStream(sourceFile) ) ) zis.use { var ze: ZipEntry? var count: Int val buffer = ByteArray(8192) while (zis.nextEntry.also { ze = it } != null) { var entryName = ze!!.name // 移除开头的斜杠,消除绝对路径 entryName = entryName.removePrefix("/") // 拦截包含目录遍历字符的不安全路径 if (entryName.contains("../") || entryName.startsWith("../")) { throw IllegalArgumentException("Invalid zip entry path: ${ze!!.name}") } val file = File(targetDirPath, entryName) val dir: File = if (ze!!.isDirectory) file else file.parentFile if (!dir.isDirectory && !dir.mkdirs()) { throw FileNotFoundException( "Failed to ensure directory: " + dir.absolutePath ) } if (ze!!.isDirectory) { continue } val fout = FileOutputStream(file) fout.use { while (zis.read(buffer).also { count = it } != -1) { sumLength += count.toLong() fout.write(buffer, 0, count) fout.flush() } } } } onSuccess?.invoke() } catch (e: Exception) { onError?.invoke(e.message) } }
补充说明
这个校验是Android 14针对应用沙箱安全的强化措施,属于系统底层的安全防护逻辑,虽未在解压相关的专项文档中单独说明,但处理Zip文件时始终对路径做安全校验是最佳实践,能避免潜在的安全风险。
内容的提问来源于stack exchange,提问作者Warm Man
相关产品推荐
相关产品推荐

