对于开发Javaweb项目来说,经常会有让用户通过浏览器上传文件的需求,比如上传用户头像(jpg格式)。那么像这样的功能我们通常的实现方式都是在前端页面先验证文件的后缀名是否是jpg格式,通过验证之后,再进行上传请求操作,接下来服务器端接受文件之后,再一次验证文件后缀名是否jpg,之后再讲文件保存到指定文件夹,具体代码如下:

<script type="text/javascript" src="js/jquery-1.11.3.js"></script>
<script type="text/javascript">// 上传文件function uploadFunc(){var file = $("#file")[0].files[0];var fileName = file.name;var suffixName = fileName.substring(fileName.lastIndexOf("."));if( suffixName != ".jpg" ){$("#info").html("请上传jpg格式图片!");return false;}var fileData = new FormData();fileData.append("file", file);fileData.append("fileName", fileName);$.ajax({url:"uploadsuffix", type:"post",data:fileData,processData:false,     contentType:false,  success:function(rt) {$("#info").html( rt.msg );}});return false;}
</script>
@MultipartConfig
@WebServlet("/uploadsuffix")
public class UploadSuffix extends HttpServlet{@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {req.setCharacterEncoding("UTF-8");resp.setCharacterEncoding("UTF-8");resp.setContentType("application/json;charset=utf-8");JSONObject json = new JSONObject();// 获取文件Part part = req.getPart("file");String fileName = req.getParameter("fileName");String suffixName = fileName.substring(fileName.lastIndexOf("."));// 文件后缀验证if( ".jpg".equals(suffixName) ){// 保存路径String clsPath = this.getClass().getResource("/").getPath();String contextPath = req.getContextPath();String filePath = clsPath.substring(0, clsPath.lastIndexOf(contextPath)) + contextPath + "/upload";InputStream in = part.getInputStream();OutputStream out = new FileOutputStream(new File( filePath + "/" + fileName));byte[] byts = new byte[1024];int len = -1;while( (len = in.read(byts)) != -1 ){out.write(byts, 0, len);}in.close();out.close();json.put("msg", "上传图片成功!");}else{json.put("msg", "请上传jpg格式图片!");}PrintWriter print = resp.getWriter();print.println( JSONObject.fromObject(json) );print.close();return;}
}

上面的常规做法的确可以验证做到对文件格式的验证,但却存在一个很大的漏洞。那就是如果用户将一个xxx.txt文件的后缀名改为xxx.jpg文件,同样也可以通过前后端的验证并且上传成功。而当我们需要用户上传头像这种功能的时候,前端通常也会将用户上传头像图片展示出来。这个时候用户上传的图片文件会就会被我们的前端代码执行。如果别有用心的用户将一个xxx.js文件改名问xxx.jpg文件,那么我们的程序将随着用户上传的文件被强行注入一个js,造成注入式攻击漏洞。相关流程如下图所示:

应该怎么去解决以上的漏洞问题呢?很明显以前单一的文件后缀验证已经无法满足了。那么我们需要转换一下验证思路。
我们都知道,不同的网络协议有对应不同的消息头。同样的,不同类型的文件类型在操作系统中被鉴别出来也需要对应的文件头。我们用UltraEdit将jpg文件打开,以十六进制内存形式表示如下图:

我们可以看到前4个字节的值为:FFD8DDE0。同样的方式打开其他的.jpg文件它的头文件前4个字节的值也相同。而换一个.png文件以同样的方式打开,前4字节为:89504E47。如下图所示:

综上所述我们可以用Java将上传图片文件头信息解析出来,和正常jpg文件头前4字节做一个对比的方式来判断文件文件类型。前端代码不变,后端代码稍作修改如下所示:

private static final Integer FILE_HEAD_LEN = 4;
private static final String JPG_HEAD = "FFD8FFE0";@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {req.setCharacterEncoding("UTF-8");resp.setCharacterEncoding("UTF-8");resp.setContentType("application/json;charset=utf-8");JSONObject json = new JSONObject();String msg = "";// 获取文件Part part = req.getPart("file");String fileName = req.getParameter("fileName");InputStream in = part.getInputStream();// 检查文件头byte[] byts = new byte[ FILE_HEAD_LEN ];in.read(byts, 0, FILE_HEAD_LEN);StringBuilder strB = new StringBuilder();for (int i = 0; i < byts.length; i++) {// 组装补码strB.append(Integer.toHexString( byts[i] & 0xff ).toUpperCase());}if( JPG_HEAD.equals(strB.toString()) ){// 合法文件String clsPath = this.getClass().getResource("/").getPath();String contextPath = req.getContextPath();String filePath = clsPath.substring(0, clsPath.lastIndexOf(contextPath)) + contextPath + "/upload";OutputStream out = new FileOutputStream(new File( filePath + "/" + fileName));in.skip(-FILE_HEAD_LEN);byts = new byte[ 1024 ];int len = -1;while( (len = in.read(byts)) != -1 ){out.write(byts, 0, len);}out.close();msg = "上传图片成功!";}else{// 非法文件msg = "请上传jpg格式图片!";}in.close();json.put("msg", msg);PrintWriter print = resp.getWriter();print.println( JSONObject.fromObject(json) );print.close();return;
}

以上,我们通过判断文件头的形式可以更好的解决单一的通过后缀名判断上传文件留下来的bug问题。上述代码中需要注意的是byts[i] & 0xff这一句,因为在计算机内的数据储存都是以二进制的补码进行存储的,所以用位与的方式可以更快速的获得计算效率。
然后还有两点是需要我们注意的:(代码就大同小异就不再演示了)

1.如果上传的是大文件如mp4,rmvb等,可以先将文件头信息上传到服务器端,通过验证之后再传剩下的部分。

2.如果上传的文件是office系列,如docx或xlsx等。这一类行的文件头比较大,只比较前4个字节是无法区分的。应该增加头文件获取的长度。

最后分享几组常见图片格式的头文件信息:
jpg:FFD8FFE0
png:89504E47
gif:47494638
bmp:424D4E9B

无论你在学习上有任何问题,重庆蜗牛学院欢迎你前来咨询,联系QQ:296799112

关于上传文件格式验证相关推荐

  1. element-ui el-upload实现上传文件以及简单的上传文件格式验证

    在后台管理系统中总是会用到上传文件的功能, 想实现的样式如下:(实现上传文件后,在input输入框显示文件名 ) 结构代码如下: <el-form-item label="使用说明&q ...

  2. 文件上传---文件上传漏洞验证的三种基本方法

    服务器如何验证上传文件格式的 文件头验证 如PE的MZ头,JPG的JFIF等等,GIF的GIF89a 文件类型验证(MIME) burp suite抓包看到上传图片类型为content-type:im ...

  3. 如何上传html验证文件大小,html5 实现客户端验证上传文件的大小(简单实例)

    在HTML 5中,现在可以在客户端进行文件上传时的校验了,比如用户选择文件后,可以 马上校验文件的大小和属性等.本文章向码农介绍html5 如何实现客户端验证上传文件的大小,感兴趣的码农可以参考一下. ...

  4. 文件上传——无验证(ctfhub 文件上传-无限制)

    文件上传漏洞最简单的就是上传小马,即一句话木马. 例如: <?php @eval($_POST['hacker']);?> 在这简单的一句话中,将会引发巨大的影响,eval函数将会把括号里 ...

  5. 文件上传-绕过/验证

    文件上传 文件上传验证 后缀名:黑名单,白名单 文件类型:MIME信息 文件头:内容头信息 相关知识 onsubmit 事件 getElementsByName类型 var类型 substring() ...

  6. KindEditor 文件上传漏洞验证

    KindEditor 文件上传漏洞 漏洞描述 影响范围 漏洞验证 漏洞修复 漏洞描述 漏洞存在于KindEditor编辑器里,你能上传.txt和.html文件,支持php/asp/jsp/asp.ne ...

  7. 微信小程序多张图片和表单一起上传,验证表单及进度条的实现完整代码

    微信小程序开发交流qq群   173683895    承接微信小程序开发.扫码加微信. 正文: 效果图: 完整代码: <!--pages/register/register.wxml--> ...

  8. java 获取上传文件的格式_js和java获取上传文件的文件名以及上传文件格式判断...

    js获取文件名: //校验 function check(){ var fileType = $("#template").val(); //判断后缀是不是需要的文件类型 if(f ...

  9. element-ui上传excel验证

    element-ui上传excel默认选固定后缀以及上传校验 //action 上传地址 //accept 点击上传后右侧所有文件的默认选择后缀 //before-upload 上传前对文件进行校验 ...

最新文章

  1. shell sh: 1: matlab: not found 解决方案
  2. JspServlet之Cookie
  3. 机器人科迪的天空_机器人科迪的天空游戏评测:我要跳的更高
  4. Boost:是否支持sse4.1指令的测试程序
  5. 《Effective Debugging:软件和系统调试的66个有效方法》一第5条:在能够正常运作的系统与发生故障的系统之间寻找差别...
  6. 收件服务器主机名未响应,邮箱收件服务器主机名是什么
  7. ios13苹方字体ttf_字体 | iOS1013 SF Compact Rounded 英文 By alex
  8. Java 并发编程之同步工具类信号量 Semaphore
  9. Pycharm报错解决:error:please select a valid Python interpreter 及一些基本设置
  10. 矩阵链乘——动态规划
  11. 英特尔:赔你15亿算了;Nvidia:反正我早就不做你那块了
  12. SVN常用基本命令windows
  13. 红警安装中出现的问题 win10,黑屏和无法联机对战(缺少ipx协议)的问题。
  14. 雷电模拟器脚本编写_你有好的引流话术, 还需配上脚本这样的全自动引流工具, 才是高效的引流方法...
  15. 【VALSE 2019 PPT】香港科技大学沈劭劼最新研究-《无人机视觉感知与导航》-总结
  16. 怎么设置邮箱自动回复?如何设置自动回复功能?
  17. 关于自然语言处理中的语义与概念
  18. 大学——留德的路01
  19. 数澜科技X浙江优创:推动平台应用双向融合,共建金融生态合作新标杆
  20. 宁夏小学三年级计算机下册教案,【宁夏三年级信息技术下册教案资讯】宁夏三年级信息技术下册教案足球知识与常识 - 足球百科 - 599比分...

热门文章

  1. tBOC-NH-PEG-SVA,甲酸叔丁酯-亚氨基-聚乙二醇-琥珀酰亚胺戊酸酯供应
  2. 专科生要怎么做才能进入阿里巴巴、百度、腾讯这样的公司?
  3. java 汉字转拼音缩写_汉字转拼音 java 工具类
  4. python将一个列表赋值给另一个列表_将一个列表分配给另一个
  5. 杨振宁:佛教与科学彻底相容
  6. 基于ICN的数据缓存
  7. 一个五年北漂的技术er,根据这些年的真实经历,给应届生的一些建议
  8. 计算一年中第几天,C语言实现
  9. JML(2021 EMNLP) 关联图像和文本
  10. socketio使用