پیمایش مسیر زیپ
با مجموعهها، منظم بمانید
ذخیره و طبقهبندی محتوا براساس اولویتهای شما.
دسته OWASP: MASVS-STORAGE: ذخیره سازی
نمای کلی
آسیبپذیری Zip Path Traversal که با نام ZipSlip نیز شناخته میشود، مربوط به مدیریت بایگانیهای فشرده است. در این صفحه، ما این آسیبپذیری را با استفاده از فرمت ZIP به عنوان مثال نشان میدهیم، اما مشکلات مشابهی ممکن است در کتابخانههایی که فرمتهای دیگر را مدیریت میکنند، مانند TAR، RAR یا 7z ایجاد شود.
دلیل اصلی این مشکل این است که در بایگانی ZIP، هر فایل بسته بندی شده با یک نام کاملاً واجد شرایط ذخیره می شود که به کاراکترهای خاصی مانند اسلش و نقطه اجازه می دهد. کتابخانه پیشفرض بسته java.util.zip
نام ورودیهای بایگانی را برای نویسههای پیمایش دایرکتوری بررسی نمیکند ( ../
)، بنابراین هنگام الحاق نام استخراجشده از بایگانی با مسیر دایرکتوری هدف باید دقت ویژهای داشت. .
بسیار مهم است که هر قطعه کد یا کتابخانه استخراج شده با ZIP را از منابع خارجی تأیید کنید. بسیاری از این گونه کتابخانه ها در برابر Zip Path Traversals آسیب پذیر هستند.
تاثیر
از آسیبپذیری Zip Path Traversal میتوان برای بازنویسی فایل دلخواه استفاده کرد. بسته به شرایط، تأثیر ممکن است متفاوت باشد، اما در بسیاری از موارد این آسیبپذیری میتواند منجر به مسائل امنیتی مهمی مانند اجرای کد شود.
اقدامات کاهشی
برای کاهش این مشکل، قبل از استخراج هر ورودی، همیشه باید بررسی کنید که مسیر هدف فرزند دایرکتوری مقصد است. کد زیر فرض میکند که دایرکتوری مقصد امن است - فقط توسط برنامه شما قابل نوشتن است و تحت کنترل مهاجم نیست - در غیر این صورت برنامه شما میتواند مستعد آسیبپذیریهای دیگر مانند حملات Symlink باشد.
کاتلین
companion object {
@Throws(IOException::class)
fun newFile(targetPath: File, zipEntry: ZipEntry): File {
val name: String = zipEntry.name
val f = File(targetPath, name)
val canonicalPath = f.canonicalPath
if (!canonicalPath.startsWith(
targetPath.canonicalPath + File.separator)) {
throw ZipException("Illegal name: $name")
}
return f
}
}
جاوا
public static File newFile(File targetPath, ZipEntry zipEntry) throws IOException {
String name = zipEntry.getName();
File f = new File(targetPath, name);
String canonicalPath = f.getCanonicalPath();
if (!canonicalPath.startsWith(targetPath.getCanonicalPath() + File.separator)) {
throw new ZipException("Illegal name: " + name);
}
return f;
}
برای جلوگیری از بازنویسی تصادفی فایلهای موجود، قبل از شروع فرآیند استخراج، باید مطمئن شوید که فهرست مقصد خالی است. در غیر این صورت شما در معرض خطر خرابی برنامه یا در موارد شدید، به خطر افتادن برنامه هستید.
کاتلین
@Throws(IOException::class)
fun unzip(inputStream: InputStream?, destinationDir: File) {
if (!destinationDir.isDirectory) {
throw IOException("Destination is not a directory.")
}
val files = destinationDir.list()
if (files != null && files.isNotEmpty()) {
throw IOException("Destination directory is not empty.")
}
ZipInputStream(inputStream).use { zipInputStream ->
var zipEntry: ZipEntry
while (zipInputStream.nextEntry.also { zipEntry = it } != null) {
val targetFile = File(destinationDir, zipEntry.name)
// ...
}
}
}
جاوا
void unzip(final InputStream inputStream, File destinationDir)
throws IOException {
if(!destinationDir.isDirectory()) {
throw IOException("Destination is not a directory.");
}
String[] files = destinationDir.list();
if(files != null && files.length != 0) {
throw IOException("Destination directory is not empty.");
}
try (ZipInputStream zipInputStream = new ZipInputStream(inputStream)) {
ZipEntry zipEntry;
while ((zipEntry = zipInputStream.getNextEntry()) != null) {
final File targetFile = new File(destinationDir, zipEntry);
…
}
}
}
منابع
{% کلمه به کلمه %}
{% آخر کلمه %} برای شما توصیه می شود
- توجه: وقتی جاوا اسکریپت خاموش است، متن پیوند نمایش داده می شود
- پیمودن مسیر
{% کلمه به کلمه %} {% آخر کلمه %}
محتوا و نمونه کدها در این صفحه مشمول پروانههای توصیفشده در پروانه محتوا هستند. جاوا و OpenJDK علامتهای تجاری یا علامتهای تجاری ثبتشده Oracle و/یا وابستههای آن هستند.
تاریخ آخرین بهروزرسانی 2025-07-29 بهوقت ساعت هماهنگ جهانی.
[null,null,["تاریخ آخرین بهروزرسانی 2025-07-29 بهوقت ساعت هماهنگ جهانی."],[],[],null,["# Zip Path Traversal\n\n\u003cbr /\u003e\n\n**OWASP category:** [MASVS-STORAGE: Storage](https://mas.owasp.org/MASVS/05-MASVS-STORAGE)\n\nOverview\n--------\n\nThe Zip Path Traversal vulnerability, also known as ZipSlip, is related to handling compressed archives. On this page, we demonstrate this vulnerability using the ZIP format as an example, but similar problems can arise in libraries handling other formats, like TAR, RAR, or 7z.\n\nThe underlying reason for this problem is that inside ZIP archives, each packed file is stored with a fully qualified name, which allows special characters such as slashes and dots. The default library from the `java.util.zip` package doesn't check the names of the archive entries for directory traversal characters (`../`), so special care must be taken when concatenating the name extracted from the archive with the targeted directory path.\n\nIt's very important to validate any ZIP-extracting code snippets or libraries from external sources. **Many such libraries are vulnerable to Zip Path Traversals.**\n\nImpact\n------\n\nThe Zip Path Traversal vulnerability can be used to achieve arbitrary file overwrite. Depending on conditions, the impact might vary, but in many cases this vulnerability can lead to major security issues such as code execution.\n\nMitigations\n-----------\n\nTo mitigate this issue, before extracting each entry, you should always verify that the target path is a child of the destination directory. The code below assumes that the destination directory is safe -- writable by your app only and not under attacker control -- otherwise your app could be prone to other vulnerabilities such as symlink attacks. \n\n### Kotlin\n\n companion object {\n @Throws(IOException::class)\n fun newFile(targetPath: File, zipEntry: ZipEntry): File {\n val name: String = zipEntry.name\n val f = File(targetPath, name)\n val canonicalPath = f.canonicalPath\n if (!canonicalPath.startsWith(\n targetPath.canonicalPath + File.separator)) {\n throw ZipException(\"Illegal name: $name\")\n }\n return f\n }\n }\n\n### Java\n\n public static File newFile(File targetPath, ZipEntry zipEntry) throws IOException {\n String name = zipEntry.getName();\n File f = new File(targetPath, name);\n String canonicalPath = f.getCanonicalPath();\n if (!canonicalPath.startsWith(targetPath.getCanonicalPath() + File.separator)) {\n throw new ZipException(\"Illegal name: \" + name);\n }\n return f;\n }\n\nTo avoid accidentally overwriting existing files, you should also make sure that the destination directory is empty before starting the extraction process. Otherwise you risk potential app crashes, or in extreme cases, an application compromise. \n\n### Kotlin\n\n @Throws(IOException::class)\n fun unzip(inputStream: InputStream?, destinationDir: File) {\n if (!destinationDir.isDirectory) {\n throw IOException(\"Destination is not a directory.\")\n }\n val files = destinationDir.list()\n if (files != null && files.isNotEmpty()) {\n throw IOException(\"Destination directory is not empty.\")\n }\n ZipInputStream(inputStream).use { zipInputStream -\u003e\n var zipEntry: ZipEntry\n while (zipInputStream.nextEntry.also { zipEntry = it } != null) {\n val targetFile = File(destinationDir, zipEntry.name)\n // ...\n }\n }\n }\n\n### Java\n\n void unzip(final InputStream inputStream, File destinationDir)\n throws IOException {\n if(!destinationDir.isDirectory()) { \n throw IOException(\"Destination is not a directory.\");\n }\n\n String[] files = destinationDir.list();\n if(files != null && files.length != 0) { \n throw IOException(\"Destination directory is not empty.\");\n }\n\n try (ZipInputStream zipInputStream = new ZipInputStream(inputStream)) {\n ZipEntry zipEntry;\n while ((zipEntry = zipInputStream.getNextEntry()) != null) {\n final File targetFile = new File(destinationDir, zipEntry);\n ...\n }\n }\n }\n\nResources\n---------\n\n- [Zip Slip Vulnerability](https://snyk.io/research/zip-slip-vulnerability)\n\nRecommended for you\n-------------------\n\n- Note: link text is displayed when JavaScript is off\n- [Path traversal](/topic/security/risks/path-traversal)"]]