feat: add path transversal security
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user