日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

spring boot 使用过滤器过滤非法字符

發(fā)布時(shí)間:2024/3/12 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 spring boot 使用过滤器过滤非法字符 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

有時(shí)候我們要配置我們自己的定義非法字符過(guò)濾,但 HttpServletRequest 對(duì)象是不可以改變的,那我們只好定義一個(gè)類,成為它的子類,重寫它的方法,這樣在Servelt中使用它方法時(shí)候,

就會(huì)進(jìn)入我們重寫方法,從而實(shí)現(xiàn)過(guò)濾

?

1、創(chuàng)建一個(gè)HTML過(guò)濾類,我過(guò)濾的是 html 和 xss,當(dāng)然你們自己定義你們的過(guò)濾規(guī)則

package io.xiongdi.common.xss;import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern;/*** @author wujiaxing* @date 2019-07-09*/ public final class HTMLFilter {/*** regex flag union representing /si modifiers in php**/private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL;private static final Pattern P_COMMENTS = Pattern.compile("<!--(.*?)-->", Pattern.DOTALL);private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI);private static final Pattern P_TAGS = Pattern.compile("<(.*?)>", Pattern.DOTALL);private static final Pattern P_END_TAG = Pattern.compile("^/([a-z0-9]+)", REGEX_FLAGS_SI);private static final Pattern P_START_TAG = Pattern.compile("^([a-z0-9]+)(.*?)(/?)$", REGEX_FLAGS_SI);private static final Pattern P_QUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)=([\"'])(.*?)\\2", REGEX_FLAGS_SI);private static final Pattern P_UNQUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)(=)([^\"\\s']+)", REGEX_FLAGS_SI);private static final Pattern P_PROTOCOL = Pattern.compile("^([^:]+):", REGEX_FLAGS_SI);private static final Pattern P_ENTITY = Pattern.compile("&#(\\d+);?");private static final Pattern P_ENTITY_UNICODE = Pattern.compile("&#x([0-9a-f]+);?");private static final Pattern P_ENCODE = Pattern.compile("%([0-9a-f]{2});?");private static final Pattern P_VALID_ENTITIES = Pattern.compile("&([^&;]*)(?=(;|&|$))");private static final Pattern P_VALID_QUOTES = Pattern.compile("(>|^)([^<]+?)(<|$)", Pattern.DOTALL);private static final Pattern P_END_ARROW = Pattern.compile("^>");private static final Pattern P_BODY_TO_END = Pattern.compile("<([^>]*?)(?=<|$)");private static final Pattern P_XML_CONTENT = Pattern.compile("(^|>)([^<]*?)(?=>)");private static final Pattern P_STRAY_LEFT_ARROW = Pattern.compile("<([^>]*?)(?=<|$)");private static final Pattern P_STRAY_RIGHT_ARROW = Pattern.compile("(^|>)([^<]*?)(?=>)");private static final Pattern P_AMP = Pattern.compile("&");private static final Pattern P_QUOTE = Pattern.compile("<");private static final Pattern P_LEFT_ARROW = Pattern.compile("<");private static final Pattern P_RIGHT_ARROW = Pattern.compile(">");private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>");private static final ConcurrentMap<String, Pattern> P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap<String, Pattern>();private static final ConcurrentMap<String, Pattern> P_REMOVE_SELF_BLANKS = new ConcurrentHashMap<String, Pattern>();/*** 一組允許的html元素,以及元素允許的屬性*/private final Map<String, List<String>> vAllowed;/*** 每個(gè)(允許的)html元素的打開(kāi)標(biāo)記數(shù)*/private final Map<String, Integer> vTagCounts = new HashMap<String, Integer>();/*** 必須總是自關(guān)閉的html元素(例如。“< img / >*/private final String[] vSelfClosingTags;/*** 必須始終具有獨(dú)立的開(kāi)始和結(jié)束標(biāo)記的html元素(例如。“< b > < / b >”)*/private final String[] vNeedClosingTags;/*** 一組不允許的html元素*/private final String[] vDisallowed;/*** 屬性,應(yīng)檢查這些屬性是否為有效協(xié)議*/private final String[] vProtocolAtts;/*** 允許協(xié)議*/private final String[] vAllowedProtocols;/*** 如果標(biāo)簽不包含任何內(nèi)容(例如"<b></b>"或"<b />")*/private final String[] vRemoveBlanks;/*** html標(biāo)記中允許的實(shí)體*/private final String[] vAllowedEntities;/*** 標(biāo)志,確定輸入字符串中是否允許注釋。*/private final boolean stripComment;/*** 編碼引用*/private final boolean encodeQuotes;private boolean vDebug = false;/*** 標(biāo)記決定是否嘗試在呈現(xiàn)“不平衡的”標(biāo)記時(shí)制作標(biāo)記* 尖括號(hào)(如。“<b text </b>”變?yōu)椤?lt;b> text </b>”)。* 如果設(shè)為false,不平衡的尖括號(hào)將被html轉(zhuǎn)義。*/private final boolean alwaysMakeTags;public HTMLFilter() {this.vAllowed = new HashMap<>();final ArrayList<String> aAtts = new ArrayList<>();aAtts.add("href");aAtts.add("target");vAllowed.put("a", aAtts);final ArrayList<String> imgAtts = new ArrayList<>();imgAtts.add("src");imgAtts.add("width");imgAtts.add("height");imgAtts.add("alt");vAllowed.put("img", imgAtts);final ArrayList<String> noAtts = new ArrayList<>();vAllowed.put("b", noAtts);vAllowed.put("strong", noAtts);vAllowed.put("i", noAtts);vAllowed.put("em", noAtts);this.vSelfClosingTags = new String[]{"img"};this.vNeedClosingTags = new String[]{"a", "b", "strong", "i", "em"};this.vDisallowed = new String[]{};this.vProtocolAtts = new String[]{"src", "href"};this.vAllowedProtocols = new String[]{"http", "mailto", "https"};this.vRemoveBlanks = new String[]{"a", "b", "strong", "i", "em"};this.vAllowedEntities = new String[]{"amp", "lt", "gt", "quot"};this.stripComment = true;this.encodeQuotes = true;this.alwaysMakeTags = true;}public HTMLFilter(boolean vDebug) {this();this.vDebug = vDebug;}/*** 帶map參數(shù)的構(gòu)造函數(shù)* assert 后面跟個(gè)冒號(hào)表達(dá)式。如果冒號(hào)前為 true,則冒號(hào)后面的被忽略。* 如果冒號(hào)前為false,則拋出AssertionError ,錯(cuò)誤信息內(nèi)容為冒號(hào)后面的內(nèi)容** @param conf 包含配置的conf映射。鍵匹配字段名*/public HTMLFilter(final Map<String, Object> conf) {assert conf.containsKey("vAllowed") : "configuration requires vAllowed";assert conf.containsKey("vSelfClosingTags") : "configuration requires vSelfClosingTags";assert conf.containsKey("vNeedClosingTags") : "configuration requires vNeedClosingTags";assert conf.containsKey("vDisallowed") : "configuration requires vDisallowed";assert conf.containsKey("vAllowedProtocols") : "configuration requires vAllowedProtocols";assert conf.containsKey("vProtocolAtts") : "configuration requires vProtocolAtts";assert conf.containsKey("vRemoveBlanks") : "configuration requires vRemoveBlanks";assert conf.containsKey("vAllowedEntities") : "configuration requires vAllowedEntities";vAllowed = Collections.unmodifiableMap((Map<String, List<String>>) conf.get("vAllowed"));vSelfClosingTags = (String[]) conf.get("vSelfClosingTags");vNeedClosingTags = (String[]) conf.get("vNeedClosingTags");vDisallowed = (String[]) conf.get("vDisallowed");vAllowedProtocols = (String[]) conf.get("vAllowedProtocols");vProtocolAtts = (String[]) conf.get("vProtocolAtts");vRemoveBlanks = (String[]) conf.get("vRemoveBlanks");vAllowedEntities = (String[]) conf.get("vAllowedEntities");stripComment = conf.containsKey("stripComment") ? (Boolean) conf.get("stripComment") : true;encodeQuotes = conf.containsKey("encodeQuotes") ? (Boolean) conf.get("encodeQuotes") : true;alwaysMakeTags = conf.containsKey("alwaysMakeTags") ? (Boolean) conf.get("alwaysMakeTags") : true;}private void reset() {vTagCounts.clear();}private void debug(final String msg) {if (vDebug) {Logger.getAnonymousLogger().info(msg);}}/*** 我的一些PHP庫(kù)函數(shù)版本** @param decimal* @return*/public static String chr(final int decimal) {return String.valueOf((char) decimal);}/*** html 的一些特殊字符進(jìn)行替換,例如 > 就替換成 &gt;** @param s* @return*/public static String htmlSpecialChars(final String s) {String result = s;result = regexReplace(P_AMP, "&amp;", result);result = regexReplace(P_QUOTE, "&quot;", result);result = regexReplace(P_LEFT_ARROW, "&lt;", result);result = regexReplace(P_RIGHT_ARROW, "&gt;", result);return result;}private static String regexReplace(final Pattern regex_pattern, final String replacement, final String s) {Matcher m = regex_pattern.matcher(s);return m.replaceAll(replacement);}public String filter(final String input) {reset();String s = input;debug("************************************************");debug(" INPUT: " + input);s = escapeComments(s);debug(" escapeComments: " + s);s = balanceHTML(s);debug(" balanceHTML: " + s);s = checkTags(s);debug(" checkTags: " + s);s = processRemoveBlanks(s);debug("processRemoveBlanks: " + s);s = validateEntities(s);debug(" validateEntites: " + s);debug("************************************************\n\n");return s;}public boolean isAlwaysMakeTags() {return alwaysMakeTags;}public boolean isStripComments() {return stripComment;}private String escapeComments(final String s) {final Matcher m = P_COMMENTS.matcher(s);final StringBuffer buf = new StringBuffer();if (m.find()) {//(.*?)final String match = m.group(1);m.appendReplacement(buf, Matcher.quoteReplacement("<!--" + htmlSpecialChars(match) + "-->"));}m.appendTail(buf);return buf.toString();}private String balanceHTML(String s) {if (alwaysMakeTags) {//// try and form html// s = regexReplace(P_END_ARROW, "", s);s = regexReplace(P_BODY_TO_END, "<$1>", s);s = regexReplace(P_XML_CONTENT, "$1<$2", s);} else {//// escape stray brackets// s = regexReplace(P_STRAY_LEFT_ARROW, "&lt;$1", s);s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2&gt;<", s);//// the last regexp causes '<>' entities to appear// (we need to do a lookahead assertion so that the last bracket can// be used in the next pass of the regexp)// s = regexReplace(P_BOTH_ARROWS, "", s);}return s;}private String checkTags(String s) {Matcher m = P_TAGS.matcher(s);final StringBuffer buf = new StringBuffer();while (m.find()) {String replaceStr = m.group(1);replaceStr = processTag(replaceStr);m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr));}m.appendTail(buf);s = buf.toString();// these get tallied in processTag// (remember to reset before subsequent calls to filter method)for (String key : vTagCounts.keySet()) {for (int ii = 0; ii < vTagCounts.get(key); ii++) {s += "</" + key + ">";}}return s;}private String processRemoveBlanks(final String s) {String result = s;for (String tag : vRemoveBlanks) {if (!P_REMOVE_PAIR_BLANKS.containsKey(tag)) {P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?></" + tag + ">"));}result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result);if (!P_REMOVE_SELF_BLANKS.containsKey(tag)) {P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>"));}result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), "", result);}return result;}private String processTag(final String s) {// ending tagsMatcher m = P_END_TAG.matcher(s);if (m.find()) {final String name = m.group(1).toLowerCase();if (allowed(name)) {if (!inArray(name, vSelfClosingTags)) {if (vTagCounts.containsKey(name)) {vTagCounts.put(name, vTagCounts.get(name) - 1);return "</" + name + ">";}}}}// starting tagsm = P_START_TAG.matcher(s);if (m.find()) {final String name = m.group(1).toLowerCase();final String body = m.group(2);String ending = m.group(3);//debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" );if (allowed(name)) {String params = "";final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body);final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body);final List<String> paramNames = new ArrayList<String>();final List<String> paramValues = new ArrayList<String>();while (m2.find()) {//([a-z0-9]+)paramNames.add(m2.group(1));//(.*?)paramValues.add(m2.group(3));}while (m3.find()) {//([a-z0-9]+)paramNames.add(m3.group(1));//([^\"\\s']+)paramValues.add(m3.group(3));}String paramName, paramValue;for (int ii = 0; ii < paramNames.size(); ii++) {paramName = paramNames.get(ii).toLowerCase();paramValue = paramValues.get(ii);if (allowedAttribute(name, paramName)) {if (inArray(paramName, vProtocolAtts)) {paramValue = processParamProtocol(paramValue);}params += " " + paramName + "=\"" + paramValue + "\"";}}if (inArray(name, vSelfClosingTags)) {ending = " /";}if (inArray(name, vNeedClosingTags)) {ending = "";}if (ending == null || ending.length() < 1) {if (vTagCounts.containsKey(name)) {vTagCounts.put(name, vTagCounts.get(name) + 1);} else {vTagCounts.put(name, 1);}} else {ending = " /";}return "<" + name + params + ending + ">";} else {return "";}}// commentsm = P_COMMENT.matcher(s);if (!stripComment && m.find()) {return "<" + m.group() + ">";}return "";}private String processParamProtocol(String s) {s = decodeEntities(s);final Matcher m = P_PROTOCOL.matcher(s);if (m.find()) {final String protocol = m.group(1);if (!inArray(protocol, vAllowedProtocols)) {// bad protocol, turn into local anchor link insteads = "#" + s.substring(protocol.length() + 1, s.length());if (s.startsWith("#//")) {s = "#" + s.substring(3, s.length());}}}return s;}private String decodeEntities(String s) {StringBuffer buf = new StringBuffer();Matcher m = P_ENTITY.matcher(s);while (m.find()) {final String match = m.group(1);final int decimal = Integer.decode(match).intValue();m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));}m.appendTail(buf);s = buf.toString();buf = new StringBuffer();m = P_ENTITY_UNICODE.matcher(s);while (m.find()) {final String match = m.group(1);final int decimal = Integer.valueOf(match, 16).intValue();m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));}m.appendTail(buf);s = buf.toString();buf = new StringBuffer();m = P_ENCODE.matcher(s);while (m.find()) {final String match = m.group(1);final int decimal = Integer.valueOf(match, 16).intValue();m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));}m.appendTail(buf);s = buf.toString();s = validateEntities(s);return s;}private String validateEntities(final String s) {StringBuffer buf = new StringBuffer();// validate entities throughout the stringMatcher m = P_VALID_ENTITIES.matcher(s);while (m.find()) {// ([^&;]*)final String one = m.group(1);// (?=(;|&|$))final String two = m.group(2);m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two)));}m.appendTail(buf);return encodeQuotes(buf.toString());}private String encodeQuotes(final String s) {if (encodeQuotes) {StringBuffer buf = new StringBuffer();Matcher m = P_VALID_QUOTES.matcher(s);while (m.find()) {// (>|^)final String one = m.group(1);// ([^<]+?)final String two = m.group(2);// (<|$)final String three = m.group(3);m.appendReplacement(buf, Matcher.quoteReplacement(one + regexReplace(P_QUOTE, "&quot;", two) + three));}m.appendTail(buf);return buf.toString();} else {return s;}}private String checkEntity(final String preamble, final String term) {return ";".equals(term) && isValidEntity(preamble)? '&' + preamble: "&amp;" + preamble;}private boolean isValidEntity(final String entity) {return inArray(entity, vAllowedEntities);}private static boolean inArray(final String s, final String[] array) {for (String item : array) {if (item != null && item.equals(s)) {return true;}}return false;}private boolean allowed(final String name) {return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed);}private boolean allowedAttribute(final String name, final String paramName) {return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName));} }

?

2、創(chuàng)建一個(gè) xss 過(guò)濾類,繼承HttpServletRequestWrapper,這個(gè)類是一個(gè)包裝類

package io.xiongdi.common.xss;import com.google.common.net.HttpHeaders; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.springframework.http.MediaType; import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.LinkedHashMap; import java.util.Map;/*** xss 過(guò)濾處理* 實(shí)現(xiàn)了HttpServletRequestWrapper的類,就可以成為HttpRequestWrapper的裝飾類* @author wujiaxing* @date 2019-07-10*/ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {/*** 沒(méi)有包裝過(guò)的 HttpServletRequest ,(特殊場(chǎng)景,需要自己過(guò)濾)*/private HttpServletRequest orgRequest;/*** html 過(guò)濾*/private final static HTMLFilter htmlFilter = new HTMLFilter();@Overridepublic Map<String, String[]> getParameterMap() {Map<String, String[]> parameterMap = super.getParameterMap();if (parameterMap.size() > 0) {Map<String, String[]> map = new LinkedHashMap<>();for (String k : parameterMap.keySet()) {String[] v = parameterMap.get("s");for (int i = 0; i < v.length; i++) {v[i] = xssEncode(v[i]);}map.put(xssEncode(k), v);}return map;}return parameterMap;}@Overridepublic String getHeader(String name) {String header = super.getHeader(xssEncode(name));if (StringUtils.isNotBlank(header)) {return xssEncode(header);}return header;}@Overridepublic ServletInputStream getInputStream() throws IOException {// 請(qǐng)求頭非json類型,直接返回,Content-Type != application/jsonif (!MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(super.getHeader(HttpHeaders.CONTENT_TYPE))) {return super.getInputStream();}// 請(qǐng)求流為空,直接返回String io = IOUtils.toString(super.getInputStream(), "UTF-8");if (StringUtils.isBlank(io)) {return super.getInputStream();}// 執(zhí)行 xss 過(guò)濾io = xssEncode(io);// 將過(guò)濾結(jié)果封裝成流final ByteArrayInputStream bio = new ByteArrayInputStream(io.getBytes("UTF-8"));return new ServletInputStream() {@Overridepublic boolean isFinished() {return true;}@Overridepublic boolean isReady() {return true;}@Overridepublic void setReadListener(ReadListener listener) {}@Overridepublic int read() throws IOException {return bio.read();}};}private String xssEncode(String input) {return htmlFilter.filter(input);}@Overridepublic String getParameter(String name) {String value = super.getParameter(xssEncode(name));if (StringUtils.isNotBlank(value)) {return xssEncode(value);}return value;}@Overridepublic String[] getParameterValues(String name) {String[] values = super.getParameterValues(xssEncode(name));if (values == null || values.length == 0) {return null;}for (int i = 0; i < values.length; i++) {values[i] = xssEncode(values[i]);}return values;}/*** Constructs a request object wrapping the given request.** @param request The request to wrap* @throws IllegalArgumentException if the request is null*/public XssHttpServletRequestWrapper(HttpServletRequest request) {super(request);this.orgRequest = request;}/*** 獲取最原始的 request* @return*/public HttpServletRequest getOrgRequest() {return orgRequest;}/*** 獲取最原始的 request* @param request* @return*/public static HttpServletRequest getOrgRequest(HttpServletRequest request) {if (request instanceof XssHttpServletRequestWrapper) {return ((XssHttpServletRequestWrapper)request).getOrgRequest();}return request;} }

?

3、正式創(chuàng)建過(guò)濾器,使用我們定義的 HttpServletRequestWrapper的子類 包裝類去替換掉它原來(lái)的 HttpServletRequest

package io.xiongdi.common.xss;import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import java.io.IOException;/*** xss 過(guò)濾** @author wujiaxing* @date 2019-07-10*/ public class XssFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request); chain.doFilter(xssRequest, response); // 這里使用的是HttpServletRequest的子類 } @Override public void destroy() { } }

?

4、將過(guò)濾器配置給 spring boot

package io.xiongdi.config;import io.xiongdi.common.xss.XssFilter; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;import javax.servlet.DispatcherType;/*** @author wujiaxing* <p>* 過(guò)濾器配置* </p>*/ @Configuration public class FilterConfig {@Beanpublic FilterRegistrationBean xssFilterRegistration() {FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();filterRegistrationBean.setFilter(new XssFilter());filterRegistrationBean.addUrlPatterns("/*");filterRegistrationBean.setDispatcherTypes(DispatcherType.REQUEST);filterRegistrationBean.setName("xssFilter");return filterRegistrationBean;} }

?

注意路徑配置成 /*

?

轉(zhuǎn)載于:https://www.cnblogs.com/wujiaxing/p/11180167.html

總結(jié)

以上是生活随笔為你收集整理的spring boot 使用过滤器过滤非法字符的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。