From fc0a9ddaf1230e1905a0ae633a750fdda247ddbb Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 9 Jul 2025 07:42:52 +0000 Subject: [PATCH] Add path validation to prevent directory traversal attacks Co-authored-by: zhijiantianya --- test_path_validation.class | Bin 0 -> 3169 bytes .../infra/enums/ErrorCodeConstants.java | 1 + .../file/core/utils/PathValidationUtils.java | 104 ++++++++++++++++ .../infra/service/file/FileServiceImpl.java | 19 ++- .../core/utils/PathValidationUtilsTest.java | 111 ++++++++++++++++++ 5 files changed, 229 insertions(+), 6 deletions(-) create mode 100644 test_path_validation.class create mode 100644 yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/PathValidationUtils.java create mode 100644 yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/PathValidationUtilsTest.java diff --git a/test_path_validation.class b/test_path_validation.class new file mode 100644 index 0000000000000000000000000000000000000000..299e5d4d4e62aaea8a9d9c5c2c2f5112020edd35 GIT binary patch literal 3169 zcmaJ@?ROMc8UJ1OWo9=M5+*D$P-rLw!Y0{;ElDv!AYFn)5};iK6Vl>jcakjGo!#zC z5>mCTN~Kj=YFkQ!ZLMfQZLrYR1*zf}k01OqJO=fXUp<~4@por8Z-=cpbDq8Tx%YYh zJ?rr1a% zLP9&F^OiOUJVbVT(j{eU+%DQ{6xh%dGu>}wVX<7xBLY>++}SKp7w@d#%NF`FkBvYrV@8}aP7qeZ!x=j@X=KtV z!%62Xfrj$N?6y+zjA>Z==Zhn-rMYjh;H6r2ZF`Uvz;^6V5YzA|b}p~Kn{{F%H$kX` zN}}mp^eAEBP@!pLyL2M0L&Ia(B~YI=#?5%nN*d0Iv@^z)?HHD03+$@k%7dO%a4v{W zbSc=a;VU3Y>)e2ryC9(Cr9&B}BUHhT#Pz;;Q5XC@XOd=K<}Zl7cw9pq`vrodrqgfQ zHjBY*H&^gQhd_rc%U3lVL@({8?VfDjnf?O1gFz@bq@fS}yjw8y86!#EYntQn3fiUO zBN~oM#i3-*a*VWPA7#Cd6^u!g|)PYSGEEa{UImXpq!3(=@JCb0G1Tj&1vS@9pY zKAO9G_THuU?_GT9U%x*;cmBn>*FOB`yYJomWKhL30xKdB6~vl{V?f1(yWljM z67ad5uY!e=%l4#-ZFqO|sMc|AlIe#ELvKIe^!SLQeENg3b;4X;VmRXMr7+>}{}8@4I=uWNV%Z!%5u z2oPAe6w~oBqmVG4nJ}%S*|m*suPZp z9Pc;s?tKLxu+J)7rMX0IqL4HXaJX@3RhnfH32cs^$8$M{a5D1!rZbjH(fMCf{IBo4 z(I^_*_B09=v+n*u(vI21lJ;5_ zL6PBuXxa*XE70^nOqEqr$nM5^lbqyfEwG^np5ta=7yZ@(~bbcBa z@H)r;3OBSZ3 z6Swg7Kaz2xzf~VBVrT||R&NofO55ZNYFa(5MT~e;MV#*EDmw#3T!Xju29=k>ilB?Cbx$2^98*u__>%MC9Cf8cX8Fo4fdN4h$=PX-f|PhL5K zcK%8ztP1}b!7zQe48=>!p4kPN%EzswLIldV`JkKx&undt3m`o& z5mb-}awLK#C4$aK1U*X>`1Nm-D*AJzs{R6LK>r?TP(MprrT>6b(_bR3)_+L4Qa_*Q zqld5dw;XP}+u`+e_(Hyr_X^gwg?zD2e`|xkh##{E-r2K0LSruM=K3RKi1X5hAI?Og)jY zN~VQRZz(O9Vp?Qoca_r;z7f_hOPAg`RPu}{2ul={wh{$lkF0=;f { + PathValidationUtils.validateAndCleanDirectory("../../etc/passwd"); + }); + + assertThrows(ServiceException.class, () -> { + PathValidationUtils.validateAndCleanDirectory("..\\..\\windows\\system32"); + }); + + assertThrows(ServiceException.class, () -> { + PathValidationUtils.validateAndCleanDirectory("....//etc/passwd"); + }); + + assertThrows(ServiceException.class, () -> { + PathValidationUtils.validateAndCleanDirectory("....\\\\windows\\system32"); + }); + } + + @Test + void testValidateAndCleanDirectory_UrlEncodedPathTraversal() { + // 测试URL编码的路径遍历攻击 + assertThrows(ServiceException.class, () -> { + PathValidationUtils.validateAndCleanDirectory("..%2f..%2fetc%2fpasswd"); + }); + + assertThrows(ServiceException.class, () -> { + PathValidationUtils.validateAndCleanDirectory("..%5c..%5cwindows%5csystem32"); + }); + + assertThrows(ServiceException.class, () -> { + PathValidationUtils.validateAndCleanDirectory("%2e%2e%2f%2e%2e%2fetc%2fpasswd"); + }); + } + + @Test + void testValidateAndCleanDirectory_AbsolutePath() { + // 测试绝对路径 + assertThrows(ServiceException.class, () -> { + PathValidationUtils.validateAndCleanDirectory("/etc/passwd"); + }); + + assertThrows(ServiceException.class, () -> { + PathValidationUtils.validateAndCleanDirectory("C:\\windows\\system32"); + }); + } + + @Test + void testValidateAndCleanDirectory_ValidComplexPath() { + String result = PathValidationUtils.validateAndCleanDirectory("uploads/2024/01/images"); + assertEquals("uploads/2024/01/images", result); + } + + @Test + void testValidateAndCleanDirectory_WithDots() { + // 测试包含点的路径(但不是路径遍历) + String result = PathValidationUtils.validateAndCleanDirectory("my.file.txt"); + assertEquals("my.file.txt", result); + } +} \ No newline at end of file