首页后端开发ASP.NET[Asp.Net Core] 网站中的XSS跨站脚本攻击和防范

[Asp.Net Core] 网站中的XSS跨站脚本攻击和防范

时间2023-11-27 17:27:03发布访客分类ASP.NET浏览865
导读:漏洞说明: 跨站脚本攻击(Cross Site Scripting ,为了不和层叠样式表(Cascading Style Sheets, CSS 的缩写混淆,故将跨站脚本攻击缩写为XSS。恶意攻击者往Web页面里插入恶意Web脚本代码(ht...

漏洞说明: 跨站脚本攻击(Cross Site Scripting),为了不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS。恶意攻击者往Web页面里插入恶意Web脚本代码(html、javascript、css等),当用户浏览该页面时,嵌入其中的Web脚本代码会被执行,从而达到恶意攻击用户的特殊目的。

测试步骤 访问系统网站,点击基础报告库进行编辑,使用Burp抓包并重新构造数据包

重新访问,成功触发了XSS弹窗

解决方法:

将危险内容过滤去除,用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 Dictionarystring, string>
     P_REMOVE_PAIR_BLANKS = new Dictionarystring, string>
    ();
    
        private static Dictionarystring, string>
     P_REMOVE_SELF_BLANKS = new Dictionarystring, 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 Dictionarystring, Liststring>
    >
 vAllowed {
     get;
     set;
 }
    

        /** counts of open tags for each (allowable) html element **/
        protected Dictionarystring, 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)
        {
    
            //ListItem>
     vAllowed = new ListItem>
    ();
    
            vAllowed = new Dictionarystring, Liststring>
    >
    ();
    
            #region 允许通过数组

            vAllowed.Add("a", new Liststring>
() {
 "target", "href", "title", "class", "style" }
    );
    
            vAllowed.Add("addr", new Liststring>
() {
 "title", "class", "style" }
    );
    
            vAllowed.Add("address", new Liststring>
() {
 "class", "style" }
    );
    
            vAllowed.Add("area", new Liststring>
() {
 "shape", "coords", "href", "alt" }
    );
    
            vAllowed.Add("article", new Liststring>
() {
 }
    );
    
            vAllowed.Add("aside", new Liststring>
() {
 }
    );
    
            vAllowed.Add("audio", new Liststring>
() {
 "autoplay", "controls", "loop", "preload", "src", "class", "style" }
    );
    
            vAllowed.Add("b", new Liststring>
() {
 "class", "style" }
    );
    
            vAllowed.Add("bdi", new Liststring>
() {
 "dir" }
    );
    
            vAllowed.Add("bdo", new Liststring>
() {
 "dir" }
    );
    
            vAllowed.Add("big", new Liststring>
() {
 }
    );
    
            vAllowed.Add("blockquote", new Liststring>
() {
 "cite", "class", "style" }
    );
    
            vAllowed.Add("br", new Liststring>
() {
 }
    );
    
            vAllowed.Add("caption", new Liststring>
() {
 "class", "style" }
    );
    
            vAllowed.Add("center", new Liststring>
() {
 }
    );
    
            vAllowed.Add("cite", new Liststring>
() {
 }
    );
    
            vAllowed.Add("code", new Liststring>
() {
 "class", "style" }
    );
    
            vAllowed.Add("col", new Liststring>
() {
 "align", "valign", "span", "width", "class", "style" }
    );
    
            vAllowed.Add("colgroup", new Liststring>
() {
 "align", "valign", "span", "width", "class", "style" }
    );
    
            vAllowed.Add("dd", new Liststring>
() {
 "class", "style" }
    );
    
            vAllowed.Add("del", new Liststring>
() {
 "datetime" }
    );
    
            vAllowed.Add("details", new Liststring>
() {
 "open" }
    );
    
            vAllowed.Add("div", new Liststring>
() {
 "class", "style" }
    );
    
            vAllowed.Add("dl", new Liststring>
() {
 "class", "style" }
    );
    
            vAllowed.Add("dt", new Liststring>
() {
 "class", "style" }
    );
    
            vAllowed.Add("em", new Liststring>
() {
 "class", "style" }
    );
    
            vAllowed.Add("font", new Liststring>
() {
 "color", "size", "face" }
    );
    
            vAllowed.Add("footer", new Liststring>
() {
 }
    );
    
            vAllowed.Add("h1", new Liststring>
() {
 "class", "style" }
    );
    
            vAllowed.Add("h2", new Liststring>
() {
 "class", "style" }
    );
    
            vAllowed.Add("h3", new Liststring>
() {
 "class", "style" }
    );
    
            vAllowed.Add("h4", new Liststring>
() {
 "class", "style" }
    );
    
            vAllowed.Add("h5", new Liststring>
() {
 "class", "style" }
    );
    
            vAllowed.Add("h6", new Liststring>
() {
 "class", "style" }
    );
    
            vAllowed.Add("header", new Liststring>
() {
 }
    );
    
            vAllowed.Add("hr", new Liststring>
() {
 }
    );
    
            vAllowed.Add("i", new Liststring>
() {
 "class", "style" }
    );
    
            vAllowed.Add("img", new Liststring>
() {
 "src", "alt", "title", "style", "width", "height", "id", "_src", "loadingclass", "class", "data-latex", "data-id", "data-type", "data-s" }
    );
    
            vAllowed.Add("ins", new Liststring>
() {
 "datetime" }
    );
    
            vAllowed.Add("li", new Liststring>
() {
 "class", "style" }
    );
    
            vAllowed.Add("mark", new Liststring>
() {
 }
    );
    
            vAllowed.Add("nav", new Liststring>
() {
 }
    );
    
            vAllowed.Add("ol", new Liststring>
() {
 "class", "style" }
    );
    
            vAllowed.Add("p", new Liststring>
() {
 "class", "style" }
    );
    
            vAllowed.Add("pre", new Liststring>
() {
 "class", "style" }
    );
    
            vAllowed.Add("s", new Liststring>
() {
 }
    );
    
            vAllowed.Add("section", new Liststring>
() {
 }
    );
    
            vAllowed.Add("small", new Liststring>
() {
 }
    );
    
            vAllowed.Add("span", new Liststring>
() {
 "class", "style" }
    );
    
            vAllowed.Add("sub", new Liststring>
() {
 "class", "style" }
    );
    
            vAllowed.Add("sup", new Liststring>
() {
 "class", "style" }
    );
    
            vAllowed.Add("strong", new Liststring>
() {
 "class", "style" }
    );
    
            vAllowed.Add("table", new Liststring>
() {
 "width", "border", "align", "valign", "class", "style" }
    );
    
            vAllowed.Add("tbody", new Liststring>
() {
 "align", "valign", "class", "style" }
    );
    
            vAllowed.Add("td", new Liststring>
() {
 "width", "rowspan", "colspan", "align", "valign", "class", "style" }
    );
    
            vAllowed.Add("tfoot", new Liststring>
() {
 "align", "valign", "class", "style" }
    );
    
            vAllowed.Add("th", new Liststring>
() {
 "width", "rowspan", "colspan", "align", "valign", "class", "style" }
    );
    
            vAllowed.Add("thead", new Liststring>
() {
 "align", "valign", "class", "style" }
    );
    
            vAllowed.Add("tr", new Liststring>
() {
 "rowspan", "align", "valign", "class", "style" }
    );
    
            vAllowed.Add("tt", new Liststring>
() {
 }
    );
    
            vAllowed.Add("u", new Liststring>
() {
 }
    );
    
            vAllowed.Add("ul", new Liststring>
() {
 "class", "style" }
    );
    
            vAllowed.Add("video", new Liststring>
() {
 "autoplay", "controls", "loop", "preload", "src", "height", "width", "class", "style" }
    );
    
            #endregion


            vDebug = debug;
    
            vTagCounts = new Dictionarystring, 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 Dictionarystring, 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 "" + (char)dec;

        }
    

        /// 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);
    
                    Liststring>
     paramNames = new Liststring>
    ();
    
                    Liststring>
     paramValues = new Liststring>
    ();

                    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 Liststring>
 parameter {
     get;
     set;
 }

        }


    }
    

在请求时对参数的内容进行过滤:

var nHtmlFilter = new NHtmlFilter(false);
    
surveyPayload.PayloadContent = nHtmlFilter.filter(surveyPayload.PayloadContent);
    

再次请求时,已将危险代码转成HTML转义字符串的形式了

声明:本文内容由网友自发贡献,本站不承担相应法律责任。对本内容有异议或投诉,请联系2913721942#qq.com核实处理,我们将尽快回复您,谢谢合作!


若转载请注明出处: [Asp.Net Core] 网站中的XSS跨站脚本攻击和防范
本文地址: https://pptw.com/jishu/557850.html
ChatGPT Plugin插件开发:基于 ASP.NET Core Minimal API ASP.NET Core WebAPI 流式返回 逐字显示

游客 回复需填写必要信息