SpringBoot后端上传文件类型检测方式
作者:牟云飞 发布时间:2021-07-02 05:00:04
标签:SpringBoot,后端,上传文件,检测
文件上传大部分通过web前端判断后尾名或者service后端判断后尾名,这种操作具有一定的风险,比如:我可以将一个jsp页面,修改后尾名改成jpg文件进行上传,由于图片预览功能,这个文件会被执行,这时就可以发送用户数据到指定的服务下,窃取用户信息。
本文通过文件流头部判断文件类型
不同的文件具有不同的头部,比如:
不同的文件具有不同的头部信息,以SpringBoot为例,通过 * 拦截文件流进行判断:
1、添加配置文件checkFileHeader.properties
在src/main/resources中增加配置文件checkFileHeader.properties,文件内容:
JPEG=FFD8FF
PNG=89504E47
GIF=47494638
TXT=75736167
PDF=255044462D312E
DOC=D0CF11E0
XML=3C3F786D6C
DOCX=504B0304
APK=504B030414000808
IPA=504B03040A000000
2、编写读取properties文件类
读取checkFileHeader.properties文件内容,用于 * 判断
/**
* 读取文件流头信息
* @author hanjie
*
*/
public class FileHeaderHelper {
private static FileHeaderHelper me ;
private static List<String> headerList ;
private FileHeaderHelper(){}
public static FileHeaderHelper getInstance(){
if(me == null){
me = new FileHeaderHelper() ;
}
return me ;
}
public List<String> getHeaderList(){
if(headerList == null){
headerList = new ArrayList<String>() ;
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
String classpathResource = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + "/fileheader.properties";
Properties p = new Properties();
try {
Resource[] res = resolver.getResources(classpathResource) ;
for (Resource re : res) {
p.load(re.getInputStream());
break ;
}
} catch (IOException e) {
e.printStackTrace();
}
for (Map.Entry<Object, Object> item : p.entrySet()) {
headerList.add(item.getValue().toString()) ;
}
}
return headerList ;
}
}
3、编写 *
拦截去中,获取文件流,读取文件流前8个字节,根据需要可以读取更多字节判读,8个字节转成16进制为16个字符串,我这里最长的APK/IPA文件也就16个字节,所以读取8个字节,读取字节后判断是否checkFileHeader.properties文件中字符串
/**
* 文件上传 *
* @author hanjie
*
*/
public class FileHeaderCheckInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
// 判断是否为文件上传请求
if (request != null && request instanceof MultipartHttpServletRequest) {
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
Map<String, MultipartFile> files = multipartRequest.getFileMap();
Iterator<String> iterator = files.keySet().iterator();
while (iterator.hasNext()) {
String formKey = (String) iterator.next();
MultipartFile multipartFile = multipartRequest.getFile(formKey);
//String filename = multipartFile.getOriginalFilename();
byte[] file = multipartFile.getBytes() ;
获取字节流前8字节,差不多够了,不行再加
int HEADER_LENGTH = 8 ;
if(file.length>HEADER_LENGTH){
//转成16进制
StringBuilder sb = new StringBuilder();
for(int i=0;i<HEADER_LENGTH;i++){
int v = file[i] & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
sb.append(0);
}
sb.append(hv);
}
boolean isFound = false ;
String fileHead = sb.toString().toUpperCase() ;
List<String> headerList = FileHeaderHelper.getInstance().getHeaderList() ;
for(String header : headerList){
if(fileHead.startsWith(header)){
isFound = true ;
break ;
}
}
if(!isFound){
// throw new BaseRunException("上传文件有异常,已被系统禁止!") ;
System.out.println("----------上传文件有异常,已被系统禁止!头部信息:"+fileHead);
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json;charset=utf-8");
PrintWriter printWriter = response.getWriter();
printWriter.write("上传文件有异常,已被系统禁止!");
return false;
}
}
}
}
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// TODO Auto-generated method stub
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// TODO Auto-generated method stub
}
}
4、配置拦截文件
* 写完了,配置下让它生效,在Configuration中配置 * ,拦截文件流进行判断
@Configuration
public class MyfWebAppConfiguration extends WebMvcConfigurerAdapter {
// * ,拦截文件流
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new FileHeaderCheckInterceptor())
.addPathPatterns("/**");
}
// //注册过滤
// @Bean
// public FilterRegistrationBean myFilterRegistration() {
//
// FilterRegistrationBean registration = new FilterRegistrationBean();
// registration.setFilter(new LoginFilter());
// registration.addUrlPatterns("/serviceInvoke");
// //registration.addInitParameter("paramName", "paramValue");
// registration.setName("loginFilter");
// registration.setOrder(1);
// return registration;
// }
//
//
// //注册servlet
// @Bean
// public ServletRegistrationBean myServletRegistration() {
// ServletRegistrationBean registration = new ServletRegistrationBean(new DownloadServlet());
// registration.addUrlMappings("/download");
// return registration;
// }
}
页面消息提醒已经在printWriter中输出了,根据自己的页面编写显示吧。
来源:https://muyunfei.blog.csdn.net/article/details/90230481


猜你喜欢
- 代码如下所示:using System;using System.Collections.Generic;using System.Linq
- 前几天在跟公司大佬讨论一个问题时,看到他使用Handler的一种方式,旁边的同事在说:以前不是这么用的啊。这个问题引发了我的好奇,虽然当时翻
- 本文实例为大家分享了flutter实现头部tabTop滚动栏的具体代码,供大家参考,具体内容如下效果图如下:main.dart代码如下:im
- 在我们移动应用开发过程中,偶尔有可能会接到这种需求:1、在手机桌面创建一个窗口,类似于360的悬浮窗口,点击这个窗口可以响应(至于窗口拖动我
- 问题描述需要定时通过websocket接口来推送mysql里面最新的数据,自定义了定时器@Component@Slf4jpublic cla
- 本文实例总结了C#子线程更新UI控件的方法,对于桌面应用程序设计的UI界面控制来说非常有实用价值。分享给大家供大家参考之用。具体分析如下:一
- 一个类,有时候搞不清楚到底用成员变量还是属性。 如: 成员变量 public string
- 面试课题 Spring boot AOPSpring boot 中 AOP是其中 重要的特性,其实现的方式借助的 * + Proxy 动态
- 本文实例讲述了Java Swing组件编程之JTable表格用法。分享给大家供大家参考,具体如下:表格是GUI编程中使用较多,但也是最麻烦的
- Android 列表组件 ListView列表组件是开发中经常用到组件,使用该组件在使用时需要为它提供适配器,由适配器提供来确定显示样式和显
- 从功能上说,可以分为两部分,分布式功能和数据功能。分布式功能主要是节点集群及集群附属功能如restful借口、集群性能检测功能等,数据功能主
- spring boot2集成activiti6踩过的坑1.activiti中的mybaitis版本冲突 错误信息Caused by: jav
- 目前较常用的分页实现办法有两种:1.每次翻页都修改SQL,向SQL传入相关参数去数据库实时查出该页的数据并显示。2.查出数据库某张表的全部数
- 一、FeignClient注解FeignClient注解被@Target(ElementType.TYPE)修饰,表示FeignClient
- 前言去年7月时,在Github发布了一个开源的Banner库,虽然Star不多,但还是有少部分人使用。Banner效果:Github链接地址
- 一、概要我们可以用java实现简单的登录界面。如上效果,直观但也需要一步一步来完成,从界面弹窗的设置,图片的插入,文本框的设置,到登录的按钮
- 记得我在以前找工作的经历中,遇到过一个面试官问过我一个很基础的问题。问题是:有一个List中有10个元素,我现在想从中删除3个元素,请问怎么
- 二叉树的深度题目:输入一颗二叉树的根节点,求该树的的深度。输入一颗二叉树的根节点,求该树的深度。从根节点到叶节点依次经过的节点(含根、叶节点
- 1、未配置之前2、开始配置 2.1 新建一个unauth.html<!DOCTYPE html><html la
- 本文实例为大家分享了java实现航空用户管理系统的具体代码,供大家参考,具体内容如下题目内容:某航空公司在其航班到达的不同的国家的不同地方设