SpringBoot后端上傳文件類型檢測方式
文件上傳大部分通過web前端判斷后尾名或者service后端判斷后尾名,這種操作具有一定的風險,比如:我可以將一個jsp頁面,修改后尾名改成jpg文件進行上傳,由于圖片預覽功能,這個文件會被執(zhí)行,這時就可以發(fā)送用戶數(shù)據(jù)到指定的服務下,竊取用戶信息。
本文通過文件流頭部判斷文件類型
不同的文件具有不同的頭部,比如:
不同的文件具有不同的頭部信息,以SpringBoot為例,通過攔截器攔截文件流進行判斷:
1、添加配置文件checkFileHeader.properties
在src/main/resources中增加配置文件checkFileHeader.properties,文件內(nèi)容:
JPEG=FFD8FF PNG=89504E47 GIF=47494638 TXT=75736167 PDF=255044462D312E DOC=D0CF11E0 XML=3C3F786D6C DOCX=504B0304 APK=504B030414000808 IPA=504B03040A000000
2、編寫讀取properties文件類
讀取checkFileHeader.properties文件內(nèi)容,用于攔截器判斷
/** ?* 讀取文件流頭信息 ?* @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個字節(jié),根據(jù)需要可以讀取更多字節(jié)判讀,8個字節(jié)轉(zhuǎn)成16進制為16個字符串,我這里最長的APK/IPA文件也就16個字節(jié),所以讀取8個字節(jié),讀取字節(jié)后判斷是否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() ; ? ? ? ? ? ? ? ?? ? ? ? ? ? ? ? ? 獲取字節(jié)流前8字節(jié),差不多夠了,不行再加 ? ? ? ? ? ? ? ? int HEADER_LENGTH = 8 ; ? ? ? ? ? ? ? ?? ? ? ? ? ? ? ? ? if(file.length>HEADER_LENGTH){ ? ? ? ? ? ? ? ? ?? ?//轉(zhuǎn)成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("上傳文件有異常,已被系統(tǒng)禁止!") ; ? ? ? ? ? ? ? ? ?? ??? ?System.out.println("----------上傳文件有異常,已被系統(tǒng)禁止!頭部信息:"+fileHead); ? ? ? ? ? ? ? ? ?? ??? ?response.setCharacterEncoding("UTF-8"); ? ? ? ? ? ? ? ? ?? ??? ?response.setContentType("application/json;charset=utf-8");? ? ? ? ? ? ? ? ? ?? ??? ?PrintWriter printWriter = response.getWriter(); ? ? ? ? ? ? ? ? ? ? ? ? ? ? printWriter.write("上傳文件有異常,已被系統(tǒng)禁止!"); ? ? ? ? ? ? ? ? ? ? ? ? ? ? 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; ? // ? ?}? }
頁面消息提醒已經(jīng)在printWriter中輸出了,根據(jù)自己的頁面編寫顯示吧。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
java 內(nèi)部類(匿名類,匿名對象,靜態(tài)內(nèi)部類)詳解及實例
這篇文章主要介紹了java 內(nèi)部類詳解及實例代碼的相關資料,需要的朋友可以參考下2016-12-12Java通過調(diào)用C/C++實現(xiàn)的DLL動態(tài)庫——JNI的方法
這篇文章主要介紹了Java通過調(diào)用C/C++實現(xiàn)的DLL動態(tài)庫——JNI的方法,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2018-01-01SpringBoot集成Zipkin實現(xiàn)分布式全鏈路監(jiān)控
這篇文章主要介紹了SpringBoot集成Zipkin實現(xiàn)分布式全鏈路監(jiān)控的方法啊,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-09-09