好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

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

文件上传大部分通过web前端判断后尾名或者service后端判断后尾名,这种操作具有一定的风险,比如:我可以将一个jsp页面,修改后尾名改成jpg文件进行上传,由于图片预览功能,这个文件会被执行,这时就可以发送用户数据到指定的服务下,窃取用户信息。

本文通过文件流头部判断文件类型

不同的文件具有不同的头部,比如:

不同的文件具有不同的头部信息,以SpringBoot为例,通过拦截器拦截文件流进行判断:

1、添加配置文件checkFileHeader.properties

在src/main/resources中增加配置文件checkFileHeader.properties,文件内容:

?

1

2

3

4

5

6

7

8

9

10

JPEG=FFD8FF

PNG=89504E47

GIF=47494638

TXT=75736167

PDF=255044462D312E

DOC=D0CF11E0

XML=3C3F786D6C

DOCX=504B0304

APK=504B030414000808

IPA=504B03040A000000

2、编写读取properties文件类

读取checkFileHeader.properties文件内容,用于拦截器判断

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

/**

  * 读取文件流头信息

  * @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文件中字符串

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

/**

  * 文件上传拦截器

  * @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中配置拦截器,拦截文件流进行判断

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

@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

查看更多关于SpringBoot后端上传文件类型检测方式的详细内容...

  阅读:29次