漏洞解决方案-文件上传

漏洞概述

非法的文件上传是黑客最常用的攻击手段之一,如果允许黑客向某个可通过 Web 访问的目录上传文件,并能够将这些文件传递给代码解释器,它会给正常的系统中执行恶意的代码文件(通常这种恶意代码叫做:WebShell),通过执行恶意的WebShell获取相应权限,来控制整个主机系统。

安全措施

限制文件扩展名

检查上传的文件扩展名是否为预期的扩展名文件,拒绝接收任何非预期的扩展名文件。

检查文件头格式

仅作文件扩展名检查,不足以识别一个文件的真正文件格式,可以进一步检查文件头,以识别上传文件的格式。不接收非预期文件头格式的文件。
常见文件的文件头(16进制,摘自百度百科,仅供参考)

JPEG (jpg),文件头:FFD8FF
PNG (png),文件头:89504E47
GIF (gif),文件头:47494638
TIFF (tif),文件头:49492A00
Windows Bitmap (bmp),文件头:424D
CAD(dwg),文件头:41433130
Adobe Photoshop (psd),文件头:38425053
Rich Text Format (rtf),文件头:7B5C727466
XML (xml),文件头:3C3F786D6C
HTML(html),文件头:68746D6C3E
Email [thorough only] (eml),文件头:44656C69766572792D646174653A
Outlook Express(dbx),文件头:CFAD12FEC5FD746F
Outlook (pst),文件头:2142444E
MS Word/Excel(xls.or.doc),文件头:D0CF11E0
MS Access (mdb),文件头:5374616E64617264204A
WordPerfect (wpd),文件头:FF575043
Adobe Acrobat (pdf),文件头:255044462D312E
Quicken (qdf),文件头:AC9EBD8F
Windows Password (pwl),文件头:E3828596
ZIP Archive (zip),文件头:504B0304
RAR Archive (rar),文件头:52617221
Wave(wav),文件头:57415645
AVI (avi),文件头:41564920
Real Audio(ram),文件头:2E7261FD
Real Media (rm),文件头:2E524D46
MPEG(mpg),文件头:000001BA
MPEG (mpg),文件头:000001B3
Quicktime(mov),文件头:6D6F6F76
Windows Media (asf),文件头:3026B2758E66CF11
MIDI(mid),文件头:4D546864

注意:文件头是可篡改的。

文件内容检查

对于文件内容格式较为固定的情况,可就文件内容做检查,进一步确保上传文件的安全性,如上传文件内容格式不满足预期,则不予接收。

随机命名文件

将接收的文件随机重命名(此举对于需要回显文件的情况没有意义)。

非WEB目录存储

对于不需要回显文件的情况,可将接收的文件保存到非WEB发布目录下,这样可以保证,即使攻击者上传了WebShell,也不可以访问执行。

代码参考

参考代码功能:
1、通过上传文件的后缀名判断上传的文件类型是否合法
2、如果合法则在根据上传文件头信息进一步判断上传文件的合法性
3、最后随机重命名上传的文件名以保证上传文件的安全性

package com.unisguard.fileupload.controller;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import com.unisguard.fileupload.service.FileCheckService;

@Controller
public class FileUploadController {

	@Autowired
	private FileCheckService fileCheckService;

	@RequestMapping("/upload")
	public String handleFormUpload(HttpServletRequest request,MultipartHttpServletRequest multipartRequest,
	                               HttpServletResponse response,Model model) throws Exception {
		try {
			StringBuilder messages = new StringBuilder();
			Iterator<String> i = multipartRequest.getFileNames();
			while(i.hasNext()) {
				MultipartFile file = multipartRequest.getFile(i.next());
				if (!file.isEmpty()) {
					InputStream source = file.getInputStream();
					// 得到上传的文件的文件名
					String fileFullName = file.getOriginalFilename();
					// 检测文件大小
					boolean isValidFileSize = fileCheckService.checkFileSize(file);
					if(!isValidFileSize) {
						messages.append("文件[").append(fileFullName).append("]上传失败,原因:文件大小超过了10M!");
						continue;
					}
					// 通过文件名检测文件后缀
					boolean isValidFileExt = fileCheckService.checkFileExt(fileFullName);
					if(!isValidFileExt) {
						messages.append("文件[").append(fileFullName).append("]上传失败,原因:文件格式不允许!");
						continue;
					}
					// 通过文件头检测文件后缀
					isValidFileExt = fileCheckService.checkFileHeaderType(file);
					if(!isValidFileExt) {
						messages.append("文件[").append(fileFullName).append("]上传失败,原因:文件格式不允许,格式可能被篡改!");
						continue;
					}
					// 获取保存服务器的文件名
					String newFileName = fileCheckService.createNewFile(fileFullName);
					// 得到上传服务器的路径
					String pathname = new StringBuilder("D:/upload/").append(newFileName).toString();
					File destination = new File(pathname);
					// 文件流写到服务器端
					FileUtils.copyInputStreamToFile(source, destination);
				}
			}
			if(messages.length() != 0) {
				model.addAttribute("message", messages.toString());
			} else{
				model.addAttribute("message", "上传成功!");
			}
		} catch (IOException e) {
			e.printStackTrace();
			throw new Exception("上传出错!",e);
		}
		return "message";
	}

}

猜你喜欢

转载自blog.csdn.net/baidu_35488871/article/details/107912454