Java文件读写防路径穿越需建立可信路径边界机制:先用Paths.get().normalize()清理路径,再用toAbsolutePath()或toRealPath()校验是否在授权根目录内,并禁用绝对路径输入、限制文件名字符及扩展名白名单。

Java 文件读写防路径穿越,关键不是“堵住所有../”,而是建立一套可信路径边界机制。核心思路是:用户输入必须落在预设根目录内,且不能逃逸——哪怕它看起来像合法文件名。
用 Paths.normalize() 做第一道过滤
不要直接拼接字符串构造路径。Java 的 Paths.get() + normalize() 能自动处理 ../、./、重复斜杠等冗余路径组件:
-
Paths.get("/var/www/uploads", "../../../etc/passwd").normalize()→/etc/passwd -
Paths.get("/var/www/uploads", "a/./b/../c").normalize()→/var/www/uploads/a/c
这步能消除大部分显性遍历,但注意:它不校验是否越界,只是让路径变“干净”。
强制检查是否在授权根目录下
规范化后,必须验证最终路径是否仍属于你的安全根目录。推荐用 toRealPath() 或 toAbsolutePath().startsWith(allowedRoot):
立即学习“Java免费学习笔记(深入)”;
- 先获取规范绝对路径:
Path resolved = path.normalize().toAbsolutePath() - 再比对前缀:
if (!resolved.startsWith(allowedBase)) { throw new SecurityException("Access denied"); } - 更严格的做法是调用
resolved.toRealPath()(会解析符号链接),再与allowedBase.toRealPath()比较
禁用绝对路径输入 + 白名单扩展名
从源头降低风险:
- 拒绝以
/(Unix)或盘符(C:\,Windows)开头的输入,直接抛异常 - 对文件名做基础校验:只允许字母、数字、下划线、短横线和点号;禁止
..、
