跨站脚本攻击(Cross Site Scripting,为了不和层叠样式表(Cascading Style Sheets, CSS的缩写混淆,故将跨站脚本攻击缩写为XSS。恶意攻击者往Web页面里插入恶意Web脚本代码(html、javascript、css等),当用户浏览该页面时,嵌入其中的Web脚本代码会被执行,从而达到恶意攻击用户的特殊目的。
访问系统网站,点击基础报告库进行编辑,使用Burp抓包并重新构造数据包
将危险内容过滤去除,用HTML转义字符串(Escape Sequence)表达的则保留
添加脚本过滤类
/// <summary>
/// Html 脚本过滤
/// </summary>
public class NHtmlFilter
{
protected static readonly RegexOptions REGEX_FLAGS_SI = RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Compiled;
private static string P_COMMENTS = "<!--(.*?-->";
private static Regex P_COMMENT = new Regex("^!--(.*--$", REGEX_FLAGS_SI;
private static string P_TAGS = "<(.*?>";
private static Regex P_END_TAG = new Regex("^/([a-z0-9]+", REGEX_FLAGS_SI;
private static Regex P_START_TAG = new Regex("^([a-z0-9]+(.*?(/?$", REGEX_FLAGS_SI;
private static Regex P_QUOTED_ATTRIBUTES = new Regex("([a-z0-9|(a-z0-9\\-a-z0-9]+=([\"'](.*?\\2", REGEX_FLAGS_SI;
private static Regex P_UNQUOTED_ATTRIBUTES = new Regex("([a-z0-9]+(=([^\"\\s']+", REGEX_FLAGS_SI;
private static Regex P_PROTOCOL = new Regex("^([^:]+:", REGEX_FLAGS_SI;
private static Regex P_ENTITY = new Regex("&#(\\d+;?";
private static Regex P_ENTITY_UNICODE = new Regex("&#x([0-9a-f]+;?";
private static Regex P_ENCODE = new Regex("%([0-9a-f]{2};?";
private static Regex P_VALID_ENTITIES = new Regex("&([^&;]*(?=(;|&|$";
private static Regex P_VALID_QUOTES = new Regex("(>|^([^<]+?(<|$", RegexOptions.Singleline | RegexOptions.Compiled;
private static string P_END_ARROW = "^>";
private static string P_BODY_TO_END = "<([^>]*?(?=<|$";
private static string P_XML_CONTENT = "(^|>([^<]*?(?=>";
private static string P_STRAY_LEFT_ARROW = "<([^>]*?(?=<|$";
private static string P_STRAY_RIGHT_ARROW = "(^|>([^<]*?(?=>";
private static string P_AMP = "&";
private static string P_QUOTE = "\"";
private static string P_LEFT_ARROW = "<";
private static string P_RIGHT_ARROW = ">";
private static string P_BOTH_ARROWS = "<>";
// @xxx could grow large... maybe use sesat's ReferenceMap
private static Dictionary<string, string> P_REMOVE_PAIR_BLANKS = new Dictionary<string, string>(;
private static Dictionary<string, string> P_REMOVE_SELF_BLANKS = new Dictionary<string, string>(;
/**
* flag determining whether to try to make tags when presented with "unbalanced"
* angle brackets (e.g. "<b text </b>" becomes "<b> text </b>". If set to false,
* unbalanced angle brackets will be html escaped.
*/
protected static bool alwaysMakeTags = true;
/**
* flag determing whether comments are allowed in input String.
*/
protected static bool stripComment = true;
/// <summary>
/// 不允许
/// </summary>
private string[] vDisallowed { get; set; }
/// <summary>
/// 允许
/// </summary>
protected Dictionary<string, List<string>> vAllowed { get; set; }
/** counts of open tags for each (allowable html element **/
protected Dictionary<string, int> vTagCounts;
/** html elements which must always be self-closing (e.g. "<img />" **/
protected string[] vSelfClosingTags;
/** html elements which must always have separate opening and closing tags (e.g. "<b></b>" **/
protected string[] vNeedClosingTags;
/** attributes which should be checked for valid protocols **/
protected string[] vProtocolAtts;
/** allowed protocols **/
protected string[] vAllowedProtocols;
/** tags which should be removed if they contain no content (e.g. "<b></b>" or "<b />" **/
protected string[] vRemoveBlanks;
/** entities allowed within html markup **/
protected string[] vAllowedEntities;
/// <summary>
/// 是否为调试
/// </summary>
protected bool vDebug;
public NHtmlFilter( : this(false { }
public NHtmlFilter(bool debug
{
//List<Item> vAllowed = new List<Item>(;
vAllowed = new Dictionary<string, List<string>>(;
#region 允许通过数组
vAllowed.Add("a", new List<string>( { "target", "href", "title", "class", "style" };
vAllowed.Add("addr", new List<string>( { "title", "class", "style" };
vAllowed.Add("address", new List<string>( { "class", "style" };
vAllowed.Add("area", new List<string>( { "shape", "coords", "href", "alt" };
vAllowed.Add("article", new List<string>( { };
vAllowed.Add("aside", new List<string>( { };
vAllowed.Add("audio", new List<string>( { "autoplay", "controls", "loop", "preload", "src", "class", "style" };
vAllowed.Add("b", new List<string>( { "class", "style" };
vAllowed.Add("bdi", new List<string>( { "dir" };
vAllowed.Add("bdo", new List<string>( { "dir" };
vAllowed.Add("big", new List<string>( { };
vAllowed.Add("blockquote", new List<string>( { "cite", "class", "style" };
vAllowed.Add("br", new List<string>( { };
vAllowed.Add("caption", new List<string>( { "class", "style" };
vAllowed.Add("center", new List<string>( { };
vAllowed.Add("cite", new List<string>( { };
vAllowed.Add("code", new List<string>( { "class", "style" };
vAllowed.Add("col", new List<string>( { "align", "valign", "span", "width", "class", "style" };
vAllowed.Add("colgroup", new List<string>( { "align", "valign", "span", "width", "class", "style" };
vAllowed.Add("dd", new List<string>( { "class", "style" };
vAllowed.Add("del", new List<string>( { "datetime" };
vAllowed.Add("details", new List<string>( { "open" };
vAllowed.Add("div", new List<string>( { "class", "style" };
vAllowed.Add("dl", new List<string>( { "class", "style" };
vAllowed.Add("dt", new List<string>( { "class", "style" };
vAllowed.Add("em", new List<string>( { "class", "style" };
vAllowed.Add("font", new List<string>( { "color", "size", "face" };
vAllowed.Add("footer", new List<string>( { };
vAllowed.Add("h2", new List<string>( { "class", "style" };
vAllowed.Add("h3", new List<string>( { "class", "style" };
vAllowed.Add("h4", new List<string>( { "class", "style" };
vAllowed.Add("h5", new List<string>( { "class", "style" };
vAllowed.Add("h5", new List<string>( { "class", "style" };
vAllowed.Add("h6", new List<string>( { "class", "style" };
vAllowed.Add("header", new List<string>( { };
vAllowed.Add("hr", new List<string>( { };
vAllowed.Add("i", new List<string>( { "class", "style" };
vAllowed.Add("img", new List<string>( { "src", "alt", "title", "style", "width", "height", "id", "_src", "loadingclass", "class", "data-latex", "data-id", "data-type", "data-s" };
vAllowed.Add("ins", new List<string>( { "datetime" };
vAllowed.Add("li", new List<string>( { "class", "style" };
vAllowed.Add("mark", new List<string>( { };
vAllowed.Add("nav", new List<string>( { };
vAllowed.Add("ol", new List<string>( { "class", "style" };
vAllowed.Add("p", new List<string>( { "class", "style" };
vAllowed.Add("pre", new List<string>( { "class", "style" };
vAllowed.Add("s", new List<string>( { };
vAllowed.Add("section", new List<string>( { };
vAllowed.Add("small", new List<string>( { };
vAllowed.Add("span", new List<string>( { "class", "style" };
vAllowed.Add("sub", new List<string>( { "class", "style" };
vAllowed.Add("sup", new List<string>( { "class", "style" };
vAllowed.Add("strong", new List<string>( { "class", "style" };
vAllowed.Add("table", new List<string>( { "width", "border", "align", "valign", "class", "style" };
vAllowed.Add("tbody", new List<string>( { "align", "valign", "class", "style" };
vAllowed.Add("td", new List<string>( { "width", "rowspan", "colspan", "align", "valign", "class", "style" };
vAllowed.Add("tfoot", new List<string>( { "align", "valign", "class", "style" };
vAllowed.Add("th", new List<string>( { "width", "rowspan", "colspan", "align", "valign", "class", "style" };
vAllowed.Add("thead", new List<string>( { "align", "valign", "class", "style" };
vAllowed.Add("tr", new List<string>( { "rowspan", "align", "valign", "class", "style" };
vAllowed.Add("tt", new List<string>( { };
vAllowed.Add("u", new List<string>( { };
vAllowed.Add("ul", new List<string>( { "class", "style" };
vAllowed.Add("video", new List<string>( { "autoplay", "controls", "loop", "preload", "src", "height", "width", "class", "style" };
#endregion
vDebug = debug;
vTagCounts = new Dictionary<string, int>(;
vSelfClosingTags = new string[] { "img" };
vNeedClosingTags = new string[] { "a", "b", "strong", "i", "em" };
vDisallowed = new string[] { "script" };
vAllowedProtocols = new string[] { "http", "mailto" }; // no ftp.
vProtocolAtts = new string[] { "src", "href" };
vRemoveBlanks = new string[] { "a", "b", "strong", "i", "em" };
vAllowedEntities = new string[] { "amp", "gt", "lt", "quot" };
stripComment = true;
alwaysMakeTags = true;
}
protected void reset(
{
vTagCounts = new Dictionary<string, int>(;
}
protected void debug(string msg
{
if (vDebug
System.Diagnostics.Debug.WriteLine(msg;
}
//---------------------------------------------------------------
// my versions of some PHP library functions
public static string chr(int dec
{
return "" + (chardec;
}
/// <summary>
/// 转换成实体字符
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static string htmlSpecialChars(string str
{
str = str.Replace(P_QUOTE, "\"";
str = str.Replace(P_LEFT_ARROW, "<";
str = str.Replace(P_RIGHT_ARROW, ">";
str = str.Replace("\n", "<br>";
return str;
}
//---------------------------------------------------------------
/**
* 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(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;
}
protected string escapeComments(string s
{
return Regex.Replace(s, P_COMMENTS, new MatchEvaluator(ConverMatchComments, RegexOptions.Singleline;
}
protected string regexReplace(string regex_pattern, string replacement, string s
{
return Regex.Replace(s, regex_pattern, replacement;
}
protected 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, "<$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 = s.Replace(P_BOTH_ARROWS, "";
}
return s;
}
protected string checkTags(string s
{
//替换不允许标签
foreach (var item in vDisallowed
{
s = Regex.Replace(s, string.Format(@"<{0}\b(.*?>(.+?</{0}>", item, "";
}
s = Regex.Replace(s, P_TAGS, new MatchEvaluator(ConverMatchTags, RegexOptions.Singleline;
// these get tallied in processTag
// (remember to reset before subsequent calls to filter method
foreach (string key in vTagCounts.Keys
{
for (int ii = 0; ii < vTagCounts[key]; ii++
{
s += "</" + key + ">";
}
}
return s;
}
protected string processRemoveBlanks(string s
{
foreach (string tag in vRemoveBlanks
{
s = regexReplace("<" + tag + "(\\s[^>]*?></" + tag + ">", "", s;
s = regexReplace("<" + tag + "(\\s[^>]*?/>", "", s;
}
return s;
}
private string processTag(string s
{
// ending tags
Match m = P_END_TAG.Match(s;
if (m.Success
{
string name = m.Groups[1].Value.ToLower(;
if (allowed(name
{
if (!inArray(name, vSelfClosingTags
{
if (vTagCounts.ContainsKey(name
{
vTagCounts[name] = vTagCounts[name] - 1;
return "</" + name + ">";
}
}
}
}
// starting tags
m = P_START_TAG.Match(s;
if (m.Success
{
string name = m.Groups[1].Value.ToLower(;
string body = m.Groups[2].Value;
string ending = m.Groups[3].Value;
//debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" ;
if (allowed(name
{
string params1 = "";
MatchCollection m2 = P_QUOTED_ATTRIBUTES.Matches(body;
MatchCollection m3 = P_UNQUOTED_ATTRIBUTES.Matches(body;
List<string> paramNames = new List<string>(;
List<string> paramValues = new List<string>(;
foreach (Match match in m2
{
paramNames.Add(match.Groups[1].Value; //([a-z0-9]+
paramValues.Add(match.Groups[3].Value; //(.*?
}
foreach (Match match in m3
{
paramNames.Add(match.Groups[1].Value; //([a-z0-9]+
paramValues.Add(match.Groups[3].Value; //([^\"\\s']+
}
string paramName, paramValue;
for (int ii = 0; ii < paramNames.Count; ii++
{
paramName = paramNames[ii].ToLower(;
paramValue = paramValues[ii];
if (allowedAttribute(name, paramName
{
if (inArray(paramName, vProtocolAtts
{
paramValue = processParamProtocol(paramValue;
}
params1 += " " + paramName + "=\"" + paramValue + "\"";
}
}
if (inArray(name, vSelfClosingTags
{
ending = " /";
}
if (inArray(name, vNeedClosingTags
{
ending = "";
}
if (ending == null || ending.Length < 1
{
if (vTagCounts.ContainsKey(name
{
vTagCounts[name] = vTagCounts[name] + 1;
}
else
{
vTagCounts.Add(name, 1;
}
}
else
{
ending = " /";
}
return "<" + name + params1 + ending + ">";
}
else
{
return "";
}
}
// comments
m = P_COMMENT.Match(s;
if (!stripComment && m.Success
{
return "<" + m.Value + ">";
}
return "";
}
private string processParamProtocol(string s
{
s = decodeEntities(s;
Match m = P_PROTOCOL.Match(s;
if (m.Success
{
string protocol = m.Groups[1].Value;
if (!inArray(protocol, vAllowedProtocols
{
// bad protocol, turn into local anchor link instead
s = "#" + s.Substring(protocol.Length + 1, s.Length - protocol.Length - 1;
if (s.StartsWith("#//"
{
s = "#" + s.Substring(3, s.Length - 3;
}
}
}
return s;
}
private string decodeEntities(string s
{
s = P_ENTITY.Replace(s, new MatchEvaluator(ConverMatchEntity;
s = P_ENTITY_UNICODE.Replace(s, new MatchEvaluator(ConverMatchEntityUnicode;
s = P_ENCODE.Replace(s, new MatchEvaluator(ConverMatchEntityUnicode;
s = validateEntities(s;
return s;
}
private string validateEntities(string s
{
s = P_VALID_ENTITIES.Replace(s, new MatchEvaluator(ConverMatchValidEntities;
s = P_VALID_QUOTES.Replace(s, new MatchEvaluator(ConverMatchValidQuotes;
return s;
}
private static bool inArray(string s, string[] array
{
foreach (string item in array
{
if (item != null && item.Equals(s
{
return true;
}
}
return false;
}
private bool allowed(string name
{
return (vAllowed.Count == 0 || vAllowed.ContainsKey(name && !inArray(name, vDisallowed;
}
private bool allowedAttribute(string name, string paramName
{
return allowed(name && (vAllowed.Count == 0 || vAllowed[name].Contains(paramName;
}
private string checkEntity(string preamble, string term
{
return ";".Equals(term && isValidEntity(preamble
? '&' + preamble
: "&" + preamble;
}
private bool isValidEntity(string entity
{
return inArray(entity, vAllowedEntities;
}
private static string ConverMatchComments(Match match
{
string matchValue = "<!--" + htmlSpecialChars(match.Groups[1].Value + "-->";
return matchValue;
}
private string ConverMatchTags(Match match
{
string matchValue = processTag(match.Groups[1].Value;
return matchValue;
}
private string ConverMatchEntity(Match match
{
string v = match.Groups[1].Value;
int decimal1 = int.Parse(v;
return chr(decimal1;
}
private string ConverMatchEntityUnicode(Match match
{
string v = match.Groups[1].Value;
int decimal1 = Convert.ToInt32("0x" + v, 16;
return chr(decimal1;
}
private string ConverMatchValidEntities(Match match
{
string one = match.Groups[1].Value; //([^&;]*
string two = match.Groups[2].Value; //(?=(;|&|$
return checkEntity(one, two;
}
private string ConverMatchValidQuotes(Match match
{
string one = match.Groups[1].Value; //(>|^
string two = match.Groups[2].Value; //([^<]+?
string three = match.Groups[3].Value;//(<|$
return one + regexReplace(P_QUOTE, "\"", two + three;
}
public bool isAlwaysMakeTags(
{
return alwaysMakeTags;
}
public bool isStripComments(
{
return stripComment;
}
class Item
{
public string name { get; set; }
public List<string> parameter { get; set; }
}
}
源代码出自:https://www.cnblogs.com/OleRookie/p/5970167.html
var nHtmlFilter = new NHtmlFilter(false;
surveyPayload.PayloadContent = nHtmlFilter.filter(surveyPayload.PayloadContent;
再次请求时,已将危险代码转成HTML转义字符串的形式了