Spring Boot教你搞定文件上传安全
创作时间:
作者:
@小白创作中心
Spring Boot教你搞定文件上传安全
引用
CSDN
等
11
来源
1.
https://blog.csdn.net/sunyuhua_keyboard/article/details/138139903
2.
https://blog.csdn.net/lkh5201314/article/details/139259942
3.
https://blog.csdn.net/qq_52748334/article/details/136786416
4.
https://blog.csdn.net/Flying_Fish_roe/article/details/142284635
5.
https://blog.csdn.net/kaka_buka/article/details/138282113
6.
https://blog.csdn.net/lkh5201314/article/details/139259611
7.
https://cloud.tencent.com/developer/article/2413773
8.
https://www.cnblogs.com/wintersun/p/18169546
9.
https://www.cnblogs.com/Chary/p/18267204
10.
https://fenglinliu.github.io/SpringBoot-%E4%B8%8A%E4%BC%A0%E6%96%87%E4%BB%B6%E5%A4%A7%E5%B0%8F%E8%AE%BE%E7%BD%AE/
11.
https://juejin.cn/post/7390620343014015028
在现代Web应用中,文件上传功能虽然便捷,但也伴随着诸多安全风险。从恶意文件上传到文件覆盖攻击,从大文件导致的DoS攻击到内容安全问题,这些隐患都可能给系统带来严重威胁。本文将基于Spring Boot框架,详细探讨如何构建安全的文件上传功能。
01
文件上传的主要安全风险
在深入具体实现之前,让我们先了解文件上传可能面临的几种主要安全风险:
- 恶意文件上传:攻击者可能上传包含恶意代码的文件,如WebShell,从而获得服务器控制权。
- 文件覆盖攻击:如果使用用户提供的文件名,可能会导致重要系统文件被覆盖。
- 大文件DoS攻击:通过上传超大文件耗尽服务器资源,导致服务不可用。
- 内容安全问题:上传的文件可能包含病毒或恶意软件,需要进行内容安全检查。
02
Spring Boot中的文件上传安全策略
1. 文件类型验证
为了防止恶意文件上传,首先需要对文件类型进行严格验证。这包括检查文件扩展名和MIME类型,确保只允许安全的文件类型通过。
String[] ALLOWED_FILE_TYPES = {"image/jpeg", "image/png", "application/pdf"};
public boolean checkFileType(MultipartFile file) {
String contentType = file.getContentType();
return Arrays.asList(ALLOWED_FILE_TYPES).contains(contentType);
}
更进一步,可以使用Apache POI等工具检查文件的实际内容,防止类型欺骗:
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.apache.poi.poifs.filesystem.FileMagic;
import org.springframework.web.multipart.MultipartFile;
public class FileValidationUtils {
private static final Map<String, String> MIME_TYPE_MAP = new HashMap<>();
public static final IllegalArgumentException INVALID_FILE_SIGNATURE = new IllegalArgumentException("Invalid file signature");
static {
MIME_TYPE_MAP.put("png", "image/png");
MIME_TYPE_MAP.put("jpeg", "image/jpeg");
MIME_TYPE_MAP.put("jpg", "image/jpeg");
MIME_TYPE_MAP.put("pdf", "application/pdf");
MIME_TYPE_MAP.put("doc", "application/msword");
MIME_TYPE_MAP.put("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
MIME_TYPE_MAP.put("xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
}
public static void validateFile(MultipartFile file) {
String contentType = file.getContentType();
if (!MIME_TYPE_MAP.containsValue(contentType)) {
throw INVALID_FILE_SIGNATURE;
}
String fileExtension = getFileExtension(file.getOriginalFilename());
String expectedMimeType = MIME_TYPE_MAP.get(fileExtension);
if (!contentType.equals(expectedMimeType)) {
throw INVALID_FILE_SIGNATURE;
}
try (InputStream is = file.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is)) {
FileMagic fileMagic = FileMagic.valueOf(bis);
if (!fileMagic.equals(FileMagic.OLE2) && !fileMagic.equals(FileMagic.OOXML) && !fileMagic.equals(FileMagic.PDF) && !fileMagic.equals(FileMagic.PNG) && !fileMagic.equals(FileMagic.JPEG)) {
throw INVALID_FILE_SIGNATURE;
}
} catch (IOException e) {
throw INVALID_FILE_SIGNATURE;
}
}
private static String getFileExtension(String fileName) {
int dotIndex = fileName.lastIndexOf('.');
if (dotIndex == -1) {
return "";
}
return fileName.substring(dotIndex + 1).toLowerCase();
}
}
2. 文件大小限制
通过配置文件限制上传文件的大小,防止大型文件上传导致的拒绝服务(DoS)攻击。
在application.properties中添加:
spring.servlet.multipart.max-file-size=2MB
spring.servlet.multipart.max-request-size=2MB
或者在application.yml中配置:
spring:
servlet:
multipart:
max-file-size: 2MB
max-request-size: 2MB
3. 防止文件覆盖
永远不要直接使用用户上传的文件名存储在服务器上,以防止路径遍历攻击。使用UUID或其他方法生成新的文件名。
import java.io.File;
import java.io.IOException;
import java.util.UUID;
import org.springframework.web.multipart.MultipartFile;
public String storeFile(MultipartFile file) {
String originalFilename = file.getOriginalFilename();
String fileExtension = getFileExtension(originalFilename);
String newFileName = UUID.randomUUID().toString() + "." + fileExtension;
File dest = new File(uploadDir + newFileName);
try {
file.transferTo(dest);
} catch (IOException e) {
throw new RuntimeException("Failed to store file", e);
}
return newFileName;
}
private String getFileExtension(String fileName) {
int dotIndex = fileName.lastIndexOf('.');
if (dotIndex == -1) {
return "";
}
return fileName.substring(dotIndex + 1).toLowerCase();
}
4. 内容安全扫描
在文件被最终保存前,使用防病毒软件扫描所有上传的文件。
public boolean scanFile(Path file) {
// 调用系统级或第三方防病毒工具进行扫描
return isFileSafe(file);
}
5. 监控和日志记录
确保所有文件上传活动都被记录下来,包括上传者的身份信息、上传时间和文件详情等。这对于追踪潜在的安全事件非常重要。
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class FileUploadLoggingInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (request.getMethod().equals("POST") && request.getRequestURI().equals("/upload")) {
MultipartFile file = request.getFile("file");
String username = request.getRemoteUser(); // 假设已登录
String ip = request.getRemoteAddr();
String timestamp = LocalDateTime.now().toString();
String logEntry = String.format("User: %s, IP: %s, Time: %s, File: %s", username, ip, timestamp, file.getOriginalFilename());
logger.info(logEntry);
}
return true;
}
}
通过上述措施,可以大幅度提高对文件上传相关漏洞的防护能力,从而保护应用和数据安全免受攻击者的利用。确保实施这些措施并定期检查和更新安全策略,以应对新出现的威胁和挑战。
热门推荐
雷达信号处理技术:从基础理论到未来展望
《新英格兰杂志》:使用CD34+造血细胞的慢病毒基因疗法治疗A型血友病
原创歌曲如何申请版权保护及推广宣传
掘金“丝路电商”新机遇 广西乘“数”而上拓蓝海
心理问题和心理疾病的区别
用设计实例看心理学如何发挥作用
昆阳之战与陨石传说:历史考证与文化解读
按字辈取名宝典:传统方法,血脉传承
Nginx常见的基本配置(全网最详细!!!)
借呗逾期9个月还能按揭买车的可能性如何?
皇后的权力与地位:历史演变下的多重角色
分手后复合的概率有多大?一篇文章帮你全面了解
我国新增3个世界地质遗产地,其中1项科研成果由江苏学者牵头
建水五大特色美食排行榜:从烧豆腐到汽锅宴,尽显古城饮食文化魅力
全面解析:新能源汽车购车指南及政策优惠详解
卤水豆腐更补钙,是真的吗?
揭秘!约翰尼·德普十大必看高分神作,好莱坞千面影帝的魅力之作盘点
北魏的六镇之乱有哪些深层次的原因?
2024届应届生突破1179万人,如何瞄准AI行业,获得高薪职业前景
增肌期的你还在避免有氧运动吗?你千万不要犯这个错误。
永安市:百舸争流齐奋进 风鹏正举逐梦行
足部疼痛?不只因肌肉和筋膜,还有易被忽视的它
二月二丨龙抬头,抬起一年好兆头
柴油车油耗增高的原因和解决方法
网购纠纷怎么办?五种解决途径全解析
七政四余和紫微斗数哪个更准,更厉害
怀孕了,哪些护肤品和化妆品最安全?这份指南帮你轻松挑选!
U20亚洲杯:国青队虽败犹荣,展现中国足球未来希望
舌头尖发麻是什么原因
《全明星街球派对》新手前三天攻略:快速积累资源的必看指南