Skip to content

Commit bef7bcc

Browse files
authored
Add security fix for unzip process (#58)
1 parent 79e322b commit bef7bcc

7 files changed

Lines changed: 77 additions & 94 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ repositories {
4545
}
4646
4747
ext {
48-
rlibVersion = "10.0.alpha11"
48+
rlibVersion = "10.0.alpha12"
4949
}
5050
5151
dependencies {

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
rootProject.version = "10.0.alpha11"
1+
rootProject.version = "10.0.alpha12"
22
group = 'javasabr.rlib'
33

44
allprojects {

gradle/libs.versions.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jakarta-mail = "2.1.3"
88
# https://mvnrepository.com/artifact/org.eclipse.angus/angus-mail
99
angus-mail = "2.0.4"
1010
# https://mvnrepository.com/artifact/org.testcontainers/testcontainers
11-
testcontainers = "1.21.3"
11+
testcontainers = "2.0.3"
1212
# https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine
1313
junit-jupiter = "6.0.1"
1414
# https://mvnrepository.com/artifact/org.projectlombok/lombok
@@ -39,4 +39,4 @@ mockito-junit-jupiter = { module = "org.mockito:mockito-junit-jupiter", version.
3939
assertj-core = { module = "org.assertj:assertj-core", version.ref = "assertj-core" }
4040

4141
[bundles]
42-
mail = ["jakarta-mail-api", "angus-mail"]
42+
mail = ["jakarta-mail-api", "angus-mail"]

rlib-common/src/main/java/javasabr/rlib/common/util/crypt/SymmetryCrypt.java

Lines changed: 0 additions & 77 deletions
This file was deleted.

rlib-common/src/main/java/javasabr/rlib/common/util/crypt/package-info.java

Lines changed: 0 additions & 4 deletions
This file was deleted.

rlib-io/src/main/java/javasabr/rlib/io/util/FileUtils.java

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -400,36 +400,37 @@ public static String getFirstFreeName(Path directory, Path file) {
400400
*
401401
* @param destination the destination folder.
402402
* @param zipFile the zip file.
403+
*
404+
* @return the count of unpacked files
403405
*/
404-
public static void unzip(Path destination, Path zipFile) {
405-
406+
public static int unzip(Path destination, Path zipFile) {
406407
if (!Files.exists(destination)) {
407408
throw new IllegalArgumentException("The folder " + destination + " doesn't exist.");
408409
}
409-
410+
Path normalizedDestination = destination.normalize();
411+
int count = 0;
410412
try (var zin = new ZipInputStream(Files.newInputStream(zipFile))) {
411413
for (var entry = zin.getNextEntry(); entry != null; entry = zin.getNextEntry()) {
412-
413414
String entryName = entry.getName();
414415
Path targetFile = destination
415416
.resolve(entryName)
416-
.toRealPath(LinkOption.NOFOLLOW_LINKS);
417-
418-
if (!targetFile.startsWith(destination)) {
417+
.normalize();
418+
if (!targetFile.startsWith(normalizedDestination)) {
419419
LOGGER.warning(entryName, "Unexpected entry name:[%s] which is outside"::formatted);
420420
continue;
421421
}
422-
423422
if (entry.isDirectory()) {
424423
Files.createDirectories(targetFile);
425424
} else {
425+
Files.createDirectories(targetFile.getParent());
426426
Files.copy(zin, targetFile, StandardCopyOption.REPLACE_EXISTING);
427+
count++;
427428
}
428429
}
429-
430430
} catch (IOException e) {
431431
throw new UncheckedIOException(e);
432432
}
433+
return count;
433434
}
434435

435436
/**

rlib-io/src/test/java/javasabr/rlib/io/FileUtilsTest.java

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22

33
import static org.assertj.core.api.Assertions.assertThat;
44

5+
import java.io.IOException;
6+
import java.nio.charset.StandardCharsets;
7+
import java.nio.file.Files;
8+
import java.nio.file.Path;
9+
import java.nio.file.StandardOpenOption;
10+
import java.util.zip.ZipEntry;
11+
import java.util.zip.ZipOutputStream;
512
import javasabr.rlib.io.util.FileUtils;
613
import org.junit.jupiter.api.Test;
714

@@ -74,4 +81,60 @@ void shouldCheckExistingExtension() {
7481
assertThat(FileUtils.hasExtension(path6)).isFalse();
7582
assertThat(FileUtils.hasExtension(path7)).isFalse();
7683
}
84+
85+
@Test
86+
void shouldUnzipFileCorrectly() throws IOException {
87+
// given:
88+
Path zipFile = Files.createTempFile("test-archive", ".zip");
89+
90+
try (var zout = new ZipOutputStream(Files.newOutputStream(zipFile, StandardOpenOption.CREATE))) {
91+
zout.putNextEntry(new ZipEntry("fileA.txt"));
92+
zout.write("test text".getBytes(StandardCharsets.UTF_8));
93+
94+
zout.putNextEntry(new ZipEntry("../fileB.txt"));
95+
zout.write("test text 2".getBytes(StandardCharsets.UTF_8));
96+
97+
ZipEntry dirAEntry = new ZipEntry("dir_a/");
98+
dirAEntry.setMethod(ZipEntry.STORED);
99+
dirAEntry.setSize(0);
100+
dirAEntry.setCrc(0);
101+
zout.putNextEntry(dirAEntry);
102+
103+
zout.putNextEntry(new ZipEntry("dir_a/fileC.txt"));
104+
zout.write("test text 3".getBytes(StandardCharsets.UTF_8));
105+
106+
zout.putNextEntry(new ZipEntry("dir_a/../fileD.txt"));
107+
zout.write("test text 4".getBytes(StandardCharsets.UTF_8));
108+
109+
zout.putNextEntry(new ZipEntry("dir_a/../../../fileE.txt"));
110+
zout.write("test text 5".getBytes(StandardCharsets.UTF_8));
111+
}
112+
113+
Path tempDirectory = Files.createTempDirectory("test-unzip");
114+
Path outputDir = tempDirectory
115+
.resolve("output")
116+
.resolve("folder");
117+
118+
Files.createDirectories(outputDir);
119+
120+
// when:
121+
int unpackedFiles = FileUtils.unzip(outputDir, zipFile);
122+
123+
// then:
124+
assertThat(unpackedFiles).isEqualTo(3);
125+
assertThat(outputDir
126+
.resolve("fileA.txt"))
127+
.exists();
128+
assertThat(outputDir
129+
.resolve("dir_a")
130+
.resolve("fileC.txt"))
131+
.exists();
132+
assertThat(tempDirectory
133+
.resolve("output")
134+
.resolve("fileB.txt"))
135+
.doesNotExist();
136+
assertThat(tempDirectory
137+
.resolve("fileE.txt"))
138+
.doesNotExist();
139+
}
77140
}

0 commit comments

Comments
 (0)