@@ -240,7 +240,7 @@ public void deleteDatasetFile(String datasetId, String fileId, String prefix) {
240240 // 删除文件时,上传到数据集中的文件会同时删除数据库中的记录和文件系统中的文件,归集过来的文件仅删除数据库中的记录
241241 if (file .getFilePath ().startsWith (dataset .getPath ())) {
242242 try {
243- Path filePath = Paths . get (file .getFilePath ());
243+ Path filePath = validateAndResolvePath (file .getFilePath (), dataset . getPath ());
244244 Files .deleteIfExists (filePath );
245245 } catch (IOException ex ) {
246246 throw BusinessException .of (SystemErrorCode .FILE_SYSTEM_ERROR );
@@ -293,8 +293,10 @@ public void batchDeleteFiles(String datasetId, BatchDeleteFilesRequest request)
293293 // 上传到数据集中的文件会同时删除数据库中的记录和文件系统中的文件,归集过来的文件仅删除数据库中的记录
294294 if (file .getFilePath ().startsWith (dataset .getPath ())) {
295295 try {
296- Path filePath = Paths . get (file .getFilePath ());
296+ Path filePath = validateAndResolvePath (file .getFilePath (), dataset . getPath ());
297297 Files .deleteIfExists (filePath );
298+ } catch (IllegalArgumentException ex ) {
299+ log .warn ("Invalid file path detected, skipping deletion: {}" , file .getFilePath ());
298300 } catch (IOException ex ) {
299301 log .error ("Failed to delete file from filesystem: {}" , file .getFilePath (), ex );
300302 }
@@ -313,7 +315,14 @@ public void batchDeleteFiles(String datasetId, BatchDeleteFilesRequest request)
313315 @ Transactional (readOnly = true )
314316 public Resource downloadFile (DatasetFile file ) {
315317 try {
316- Path filePath = Paths .get (file .getFilePath ()).normalize ();
318+ // 获取对应的数据集以验证路径安全性
319+ Dataset dataset = datasetRepository .getById (file .getDatasetId ());
320+ if (dataset == null ) {
321+ throw new RuntimeException ("Dataset not found for file: " + file .getFileName ());
322+ }
323+
324+ // 验证路径安全性,防止路径遍历攻击
325+ Path filePath = validateAndResolvePath (file .getFilePath (), dataset .getPath ());
317326 log .info ("start download file {}" , file .getFilePath ());
318327 Resource resource = new UrlResource (filePath .toUri ());
319328 if (resource .exists ()) {
@@ -931,8 +940,24 @@ private void addFile(String sourPath, String targetPath, boolean softAdd) {
931940 if (StringUtils .isBlank (sourPath ) || StringUtils .isBlank (targetPath )) {
932941 return ;
933942 }
934- Path source = Paths .get (sourPath ).normalize ();
935- Path target = Paths .get (targetPath ).normalize ();
943+
944+ // 规范化并验证源文件路径
945+ Path source ;
946+ try {
947+ source = Paths .get (sourPath ).normalize ();
948+ } catch (Exception e ) {
949+ log .warn ("Invalid source file path: {}" , sourPath );
950+ throw BusinessException .of (SystemErrorCode .FILE_SYSTEM_ERROR );
951+ }
952+
953+ // 规范化并验证目标文件路径
954+ Path target ;
955+ try {
956+ target = Paths .get (targetPath ).normalize ();
957+ } catch (Exception e ) {
958+ log .warn ("Invalid target file path: {}" , targetPath );
959+ throw BusinessException .of (SystemErrorCode .FILE_SYSTEM_ERROR );
960+ }
936961
937962 // 检查源文件是否存在且为普通文件
938963 if (!Files .exists (source ) || !Files .isRegularFile (source )) {
@@ -990,4 +1015,30 @@ private static DatasetFile getDatasetFileForAdd(AddFilesRequest req, AddFilesReq
9901015 .metadata (objectMapper .writeValueAsString (file .getMetadata ()))
9911016 .build ();
9921017 }
1018+
1019+ /**
1020+ * 安全地验证并获取文件路径,防止路径遍历攻击
1021+ *
1022+ * @param filePath 用户提供的文件路径
1023+ * @param basePath 允许的基础路径(数据集路径)
1024+ * @return 规范化后的绝对路径
1025+ * @throws IllegalArgumentException 如果路径不在基础路径内
1026+ */
1027+ private Path validateAndResolvePath (String filePath , String basePath ) {
1028+ if (StringUtils .isEmpty (filePath )) {
1029+ throw new IllegalArgumentException ("File path cannot be empty" );
1030+ }
1031+
1032+ Path normalizedPath = Paths .get (filePath ).normalize ();
1033+ Path normalizedBasePath = Paths .get (basePath ).normalize ();
1034+
1035+ // 验证规范化后的路径是否在基础路径内
1036+ if (!normalizedPath .startsWith (normalizedBasePath )) {
1037+ throw new IllegalArgumentException (
1038+ "File path is outside the allowed directory: " + filePath
1039+ );
1040+ }
1041+
1042+ return normalizedPath ;
1043+ }
9931044}
0 commit comments