diff --git a/src/main/java/local/epul4a/fotosharing/service/impl/PhotoServiceImpl.java b/src/main/java/local/epul4a/fotosharing/service/impl/PhotoServiceImpl.java index 3159fb6..b2e8554 100644 --- a/src/main/java/local/epul4a/fotosharing/service/impl/PhotoServiceImpl.java +++ b/src/main/java/local/epul4a/fotosharing/service/impl/PhotoServiceImpl.java @@ -71,10 +71,18 @@ public class PhotoServiceImpl implements PhotoService { // ========= SAUVEGARDE ORIGINAL ========= Path originalPath = uploadPath.resolve(uuid); + + // ========= PROTECTION PATH TRAVERSAL ========= + // Empêche un pirate d'envoyer ../../windows/system32 par exemple + FileValidator.validatePathTraversal(originalPath, uploadPath); + Files.write(originalPath, bytes); // ========= MINIATURE ========= String thumbUuid = "thumb-" + uuid + ".jpg"; Path thumbPath = uploadPath.resolve(thumbUuid); + + // ========= PROTECTION PATH TRAVERSAL POUR MINIATURE ========= + FileValidator.validatePathTraversal(thumbPath, uploadPath); try (ByteArrayInputStream bis = new ByteArrayInputStream(bytes)) { net.coobird.thumbnailator.Thumbnails.of(bis) .size(300, 300) diff --git a/src/main/java/local/epul4a/fotosharing/util/FileValidator.java b/src/main/java/local/epul4a/fotosharing/util/FileValidator.java index c8a5bb9..4064f7b 100644 --- a/src/main/java/local/epul4a/fotosharing/util/FileValidator.java +++ b/src/main/java/local/epul4a/fotosharing/util/FileValidator.java @@ -5,6 +5,7 @@ import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.io.InputStream; +import java.nio.file.Path; import java.util.Arrays; import java.util.List; @@ -12,6 +13,7 @@ import java.util.List; * Utilitaire pour valider les fichiers uploadés * - Vérification du type MIME réel via Magic Numbers (Apache Tika) * - Limitation de taille + * - Protection contre Path Traversal */ public class FileValidator { @@ -85,6 +87,25 @@ public class FileValidator { } } + /** + * Valide que le chemin de destination est bien dans le répertoire autorisé + * Protection contre les attaques Path Traversal (ex: ../../windows/system32) + * + * @param destinationFile Le chemin du fichier de destination + * @param rootDirectory Le répertoire racine autorisé + * @throws InvalidFileException Si le chemin tente de sortir du répertoire autorisé + */ + public static void validatePathTraversal(Path destinationFile, Path rootDirectory) throws InvalidFileException { + Path normalizedDestination = destinationFile.normalize().toAbsolutePath(); + Path normalizedRoot = rootDirectory.normalize().toAbsolutePath(); + + if (!normalizedDestination.startsWith(normalizedRoot)) { + throw new InvalidFileException( + "Chemin de fichier invalide : tentative de Path Traversal détectée" + ); + } + } + /** * Exception personnalisée pour les fichiers invalides */ diff --git a/src/test/java/local/epul4a/fotosharing/util/FileValidatorTest.java b/src/test/java/local/epul4a/fotosharing/util/FileValidatorTest.java index e1cceca..eb64e0f 100644 --- a/src/test/java/local/epul4a/fotosharing/util/FileValidatorTest.java +++ b/src/test/java/local/epul4a/fotosharing/util/FileValidatorTest.java @@ -1,12 +1,18 @@ package local.epul4a.fotosharing.util; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import org.springframework.mock.web.MockMultipartFile; +import java.nio.file.Path; + import static org.junit.jupiter.api.Assertions.*; class FileValidatorTest { + @TempDir + Path tempDir; + @Test void testValidJpegFile() { // JPEG Magic Number: FF D8 FF @@ -80,5 +86,39 @@ class FileValidatorTest { assertTrue(exception.getMessage().contains("vide")); } + + @Test + void testPathTraversalAttackDetected() { + // Tentative de Path Traversal avec ../../ + Path maliciousPath = tempDir.resolve("../../etc/passwd"); + + FileValidator.InvalidFileException exception = assertThrows( + FileValidator.InvalidFileException.class, + () -> FileValidator.validatePathTraversal(maliciousPath, tempDir) + ); + + assertTrue(exception.getMessage().contains("Path Traversal")); + } + + @Test + void testValidPathInsideRoot() { + // Chemin valide à l'intérieur du répertoire racine + Path validPath = tempDir.resolve("uploads/photo.jpg"); + + assertDoesNotThrow(() -> FileValidator.validatePathTraversal(validPath, tempDir)); + } + + @Test + void testPathTraversalWithMultipleLevels() { + // Tentative de Path Traversal avec plusieurs niveaux + Path maliciousPath = tempDir.resolve("subdir/../../../etc/passwd"); + + FileValidator.InvalidFileException exception = assertThrows( + FileValidator.InvalidFileException.class, + () -> FileValidator.validatePathTraversal(maliciousPath, tempDir) + ); + + assertTrue(exception.getMessage().contains("Path Traversal")); + } }