SpringBoot后端上传文件类型检测方式

 更新时间:2022年03月24日 10:38:19   作者:牟云飞  
这篇文章主要介绍了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中输出了,根据自己的页面编写显示吧。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java面试题冲刺第二十六天--实战编程

    Java面试题冲刺第二十六天--实战编程

    这篇文章主要为大家分享了最有价值的三道java实战面试题,涵盖内容全面,包括数据结构和算法相关的题目、经典面试编程题等,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • 深入理解Java设计模式之代理模式

    深入理解Java设计模式之代理模式

    这篇文章主要介绍了Java设计模式之代理模式的的相关资料,文中示例代码非常详细,供大家参考和学习,感兴趣的朋友可以了解下
    2021-11-11
  • Java中Session的详解

    Java中Session的详解

    这篇文章主要介绍了了解java中的session的相关问题,什么是session,session怎么用等,具有一定参考价值,需要的朋友可以了解下。
    2021-10-10
  • SpringBoot Validation快速实现数据校验的示例代码

    SpringBoot Validation快速实现数据校验的示例代码

    在实际开发中,肯定会经常遇到对参数字段进行校验的场景,通常我们只能写大量的if else来完成校验工作,而如果使用SpringBoot Validation则可以轻松的通过注解来完成,接下来小编给大家介绍下利用SpringBoot Validation快速实现数据校验的示例代码,需要的朋友参考下吧
    2022-06-06
  • Java8新特性之接口中的默认方法和静态方法详解

    Java8新特性之接口中的默认方法和静态方法详解

    今天带大家学习的是Java8新特性的相关知识,文章围绕着Java接口中的默认方法和静态方法展开,文中有非常详细的的代码示例,需要的朋友可以参考下
    2021-06-06
  • SpringMVC利用dropzone组件实现图片上传

    SpringMVC利用dropzone组件实现图片上传

    这篇文章主要介绍了SpringMVC利用dropzone组件实现图片上传,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-02-02
  • java17日期周期格式化处理方案

    java17日期周期格式化处理方案

    Java17引入了新的日期时间格式化模式B,用于表示一天中的时间段,如上午、下午、晚上等,该模式根据CLDR定义,在不同语言环境下,该模式的输出结果会有所不同,本文给大家介绍java17日期周期格式化处理方案,感兴趣的朋友跟随小编一起看看吧
    2025-01-01
  • Java中的IO读写原理详解

    Java中的IO读写原理详解

    这篇文章主要介绍了Java中的IO读写原理,IO是指输入和输出操作的技术,它提供了一组用于读取和写入数据的类,以及用于处理字符和字节数据的接口,这些类和接口可以用于读取和写入文件、网络流、内存缓冲区等各种数据源和目标,需要的朋友可以参考下
    2023-08-08
  • 学习Java模拟实现百度文档在线浏览

    学习Java模拟实现百度文档在线浏览

    这片文章介绍了如何使用Java模拟实现百度文档在线浏览,文章思路清晰,需要的朋友可以参考下
    2015-07-07
  • java中跨域问题解决的几种方式

    java中跨域问题解决的几种方式

    这篇文章主要给大家介绍了关于java中跨域问题解决的几种方式, 在前后端分离项目中,经常会遇到跨域问题,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-07-07

最新评论