必须规范化文件名再校验后缀——先剥离路径、转小写,再提取带点扩展名(如“.pdf”)与白名单精确匹配,避免大小写、多余点号、路径遍历及伪扩展名等安全风险。
直接用 string.endswith() 检查文件后缀是否在白名单中,**不安全也不可靠**——它无法处理大小写差异、多余点号、路径干扰或隐藏扩展名等问题。必须配合规范化处理才能用于实际校验。
先统一转小写再比对
用户可能上传 Report.PDF 或 image.JPEG,而白名单通常是小写(如 ["pdf", "jpg", "png"])。endsWith() 区分大小写,所以得先把文件名转小写:
- 取文件名(去除完整路径):用
lastIndexOf('/')或lastIndexOf('\')找最后一个分隔符,截取末尾部分 - 再用
toLowerCase()统一格式 - 然后对每个白名单后缀调用
endsWith("." + suffix)
注意点号位置,避免误判
"archive.tar.gz".endsWith("gz") 返回 true,但 "gz" 并非合法后缀——它只是末尾字符,不是带点的扩展名。正确做法是检查 ".gz" 是否精确出现在末尾,且前面必须是点号:
- 推荐:用
filename.toLowerCase().endsWith(".pdf")等明确带点的字符串 - 更健壮:提取扩展名再比对(如
const ext = filename.slice(filename.lastIndexOf('.'))),再查是否在白名单中
防御路径遍历和异常格式
用户可能伪造文件名如 "../malware.exe" 或 "script.js."(末尾带点),endsWith() 会漏掉这些风险:
- 先用正则或
path.basename()(Node.js)剥离路径,只保留原始文件名 - 过滤空扩展名或纯点号(如
"file."、"."、"..") - 确保扩展名至少含一个字母数字字符,拒绝
". "、".123"等非常规后缀
推荐组合写法(简洁安全)
不依赖第三方库,几行代码即可完成基础校验:
function isValidExtension(filename, whitelist) {
const name = filename.replace(/^.*[\/]/, '').toLowerCase();
const ext = name.slice(name.lastIndexOf('.'));
return whitelist.map(s => '.' + s.toLowerCase()).includes(ext);
}
// 使用:isValidExtension("Data.xlsx", ["xlsx", "csv", "pdf"]) → true

















