XSS 跨站脚本攻击预防(文件上传)

时间:2024-06-07 13:12:40
package com.aspire.sslca.cms.manage.util; import cn.hutool.extra.spring.SpringUtil; import com.aspire.webbas.common.lang.exception.ConditionNoPassException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.autoconfigure.web.servlet.MultipartProperties; import org.springframework.web.multipart.MultipartFile; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Map; import java.util.regex.Pattern; public class FileUploadCheckUtils { private static final Logger log = LoggerFactory.getLogger(FileUploadCheckUtils.class); private static final MultipartProperties multipartProperties = SpringUtil.getBean(MultipartProperties.class); // 文件类型常量 public static final String JPEG = "jpeg"; public static final String JPG = "jpg"; public static final String PNG = "png"; public static final String GIF = "gif"; public static final String PDF = "pdf"; public static final String ZIP = "zip"; public static final String RAR = "rar"; public static final String DOC = "doc"; public static final String DOCX = "docx"; public static final String XLS = "xls"; public static final String XLSX = "xlsx"; public static final String PPT = "ppt"; public static final String PPTX = "pptx"; // 魔数常量 public static final String JPEG_MAGIC = "FFD8FF"; public static final String JPG_MAGIC = "FFD8FF"; public static final String PNG_MAGIC = "89504E47"; public static final String GIF_MAGIC = "47494638"; public static final String PDF_MAGIC = "25504446"; public static final String ZIP_MAGIC = "504B0304"; public static final String RAR_MAGIC = "52617221"; public static final String DOC_MAGIC = "D0CF11E0"; public static final String DOCX_MAGIC = "504B0304"; public static final String XLS_MAGIC = "D0CF11E0"; public static final String XLSX_MAGIC = "504B0304"; public static final String PPT_MAGIC = "D0CF11E0"; public static final String PPTX_MAGIC = "504B0304"; // 允许的文件类型 // key-value : 文件类型-文件魔数 private static final Map<String, String> FILE_TYPE_MAGIC_NUMBERS = new HashMap<>(); static { FILE_TYPE_MAGIC_NUMBERS.put(JPEG, JPEG_MAGIC); FILE_TYPE_MAGIC_NUMBERS.put(JPG, JPG_MAGIC); FILE_TYPE_MAGIC_NUMBERS.put(PNG, PNG_MAGIC); FILE_TYPE_MAGIC_NUMBERS.put(GIF, GIF_MAGIC); FILE_TYPE_MAGIC_NUMBERS.put(PDF, PDF_MAGIC); FILE_TYPE_MAGIC_NUMBERS.put(ZIP, ZIP_MAGIC); FILE_TYPE_MAGIC_NUMBERS.put(RAR, RAR_MAGIC); FILE_TYPE_MAGIC_NUMBERS.put(DOC, DOC_MAGIC); FILE_TYPE_MAGIC_NUMBERS.put(DOCX, DOCX_MAGIC); FILE_TYPE_MAGIC_NUMBERS.put(XLS, XLS_MAGIC); FILE_TYPE_MAGIC_NUMBERS.put(XLSX, XLSX_MAGIC); FILE_TYPE_MAGIC_NUMBERS.put(PPT, PPT_MAGIC); FILE_TYPE_MAGIC_NUMBERS.put(PPTX, PPTX_MAGIC); } // 定义更加全面的XSS攻击模式 private static final Pattern[] XSS_PATTERNS = new Pattern[]{ // 匹配script标签 Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE), Pattern.compile("<script(.*?)>(.*?)</script>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("</script>", Pattern.CASE_INSENSITIVE), Pattern.compile("<script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), // 匹配img、iframe、embed、object标签中的恶意代码 Pattern.compile("<img(.*?)src[\r\n]*=[\r\n]*\\'(.*?)\\'(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("<img(.*?)src[\r\n]*=[\r\n]*\\\"(.*?)\\\"(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("<iframe(.*?)src[\r\n]*=[\r\n]*\\'(.*?)\\'(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("<iframe(.*?)src[\r\n]*=[\r\n]*\\\"(.*?)\\\"(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("<embed(.*?)src[\r\n]*=[\r\n]*\\'(.*?)\\'(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("<embed(.*?)src[\r\n]*=[\r\n]*\\\"(.*?)\\\"(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("<object(.*?)data[\r\n]*=[\r\n]*\\'(.*?)\\'(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("<object(.*?)data[\r\n]*=[\r\n]*\\\"(.*?)\\\"(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), // 匹配JavaScript事件处理程序 Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("onerror(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("onmouseover(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("onclick(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("onfocus(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("onblur(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("onchange(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("onsubmit(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("onreset(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("onselect(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("onunload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("onkeydown(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("onkeyup(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("onkeypress(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), // 匹配其他危险的JavaScript代码 Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("expression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE), Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE), Pattern.compile("data:text/html", Pattern.CASE_INSENSITIVE), Pattern.compile("document.cookie", Pattern.CASE_INSENSITIVE), Pattern.compile("document.write", Pattern.CASE_INSENSITIVE), Pattern.compile("window.location", Pattern.CASE_INSENSITIVE), Pattern.compile("window.open", Pattern.CASE_INSENSITIVE), Pattern.compile("innerHTML", Pattern.CASE_INSENSITIVE), Pattern.compile("alert\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("prompt\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("confirm\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), // 匹配各种形式的javascript关键字 Pattern.compile("/javascript", Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("/JS", Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("/JavaScript", Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("/jscript", Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("/vbscript", Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("/ecmascript", Pattern.MULTILINE | Pattern.DOTALL), // 匹配 CSS 表达式 Pattern.compile("style=(.*?)/\\*<style>\\*/", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("style=(.*?)expression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("style=(.*?)behaviour\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("style=(.*?)javascript:(.*?)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), // 匹配 HTML 属性中的 JavaScript Pattern.compile("href[\r\n]*=[\r\n]*\\\"(javascript:(.*?))\\\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("href[\r\n]*=[\r\n]*\\'(javascript:(.*?))\\'", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("src[\r\n]*=[\r\n]*\\\"(javascript:(.*?))\\\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("src[\r\n]*=[\r\n]*\\'(javascript:(.*?))\\'", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), // 匹配形式如 <a οnlοad=evil() /> 的 XSS Pattern.compile("<(.*?)on(load|error|mouseover|click|focus|blur|change|submit|reset|select|unload|keydown|keyup|keypress)=(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), // 匹配 base64 数据 URI Pattern.compile("data:text/html;base64,", Pattern.CASE_INSENSITIVE), // 匹配可能的路径级 XSS Pattern.compile("/[a-zA-Z0-9\\-_]*[jJ][aA][vV][aA][sS][cC][rR][iI][pP][tT]/"), Pattern.compile("/[a-zA-Z0-9\\-_]*[vV][bB][sS][cC][rR][iI][pP][tT]/"), Pattern.compile("/[a-zA-Z0-9\\-_]*[eE][cC][mM][aA][sS][cC][rR][iI][pP][tT]/"), // 匹配 XSS 关键字在任何位置的情况 Pattern.compile("[aA][lL][eE][rR][tT]\\("),