1. 什么是XSS

XSS是指恶意攻击者往Web页面里插入恶意html代码,当用户浏览该页之时,嵌入其中Web里面的html代码会被执行,从而达到恶意用户的特殊目的。

在web蓬勃发展的今天,xss毫无疑问已经变成最“流行”的漏洞. 可以经常见到互联网公司如腾讯,新浪,百度,搜狐等等的xss漏洞报告.

当然这里的方法并非完美无缺。

但是对于防范那些入门级别的hacker,我觉得还是比较靠谱的。

也欢迎大家提出意见.

2. 防范XSS

1)   asp.net 的validateRequest

该特性是ASP.Net 1.1后引入的,微软真是考虑周到,连这个都为广大的asp.net程序员想好了。validateRequest的默认值为true。当用户试图用<xxxx>之类的输入影响页面返回结果的时候,ASP.Net的引擎会引发一个 HttpRequestValidationExceptioin。默认情况下会返回如下文字的页面:

Server Error in '/YourApplicationPath' Application

A potentially dangerous Request.Form value was detected from the client

相信很多人看到这个错误后会直接把validateRequest设置成false.

这样做比较危险。

下面说说怎么替换掉这个报错页面。这里用httpModule来做,不过这里的做法也是比较粗糙的,至少大型的门户网站是没有这样做的,不过对于一些中小型的,对用户体验要求不是很严格的。可以采用这种方法。

上代码:

 

public class ExceptionModule : IHttpModule

    { 

        public void Init(HttpApplication context)

        {

            context.Error += ErrosHanlder;

        } 

        private static void ErrosHanlder(object sender, EventArgs e)

        {

            Exception exception = HttpContext.Current.Server.GetLastError();

            if (exception == null) return;

 

            if (exception is HttpRequestValidationException)

            {

                HttpContext.Current.Response.Write("<script>alert('您输入了非法字符!');window.history.go(-1);</script>");

                HttpContext.Current.Response.End();

            }

            else if (Is404Exception(exception))

            {

                LogEntry entry = new LogEntry();

                entry.Message = exception.StackTrace;

                entry.Title = exception.Message;

                entry.TimeStamp = DateTime.Now;

                entry.Severity = TraceEventType.Warning;

                Logger.Write(entry);

            }

            else

            {

                LogEntry entry = new LogEntry();

                entry.Message = exception.StackTrace;

                entry.Title = exception.Message;

                entry.TimeStamp = DateTime.Now;

                entry.Severity = TraceEventType.Error;

                Logger.Write(entry);

            }

        } 

        private static bool Is404Exception(Exception exception)

        {

            if (!(exception is HttpException)) return false;

            return (exception as HttpException).GetHttpCode() == 404;

        }

2)  validateRequest = false 的时候怎么办?

 

对于一些程序,用户必须要能够输入html代码,比如新闻发布系统,那么这种情况如果防止xss呢?

目前.net平台来说,比较好的方法是采用MS 的AntiXSSLibrary.

它采用了白名单的方式来防范XSS。

目前的版本是4.0

下载地址为:

http://www.microsoft.com/downloads/en/details.aspx?FamilyID=f4cd231b-7e06-445b-bec7-343e5884e651

可以调用GetSafeHtmlFragment / GetSafeHtml来消除html代码的有害部分。

这里又有两种选择:

a.在保存到数据库之前调用GetSafeHtmlFragment / GetSafeHtml

b.在页面上显示数据的时候调用GetSafeHtmlFragment / GetSafeHtml。

一般来说方法b好于a.但是 莆田物流网 采用了a.原因请看第三点。

   对于那些允许输入html 标记的,但是显示出来就是当初用户输入的功能,在显示数据的时候还需要调用

     AntiXss.HtmlEncode

   AntiXss.HtmlEncode和asp.net 中的HttpUtility.HtmlEncode功能基本一样

区别在于 AntiXss.HtmlEncode采用白名单

HttpUtility.HtmlEncode采用黑名单。

如果你使用了AntiXss,那么应该优先采用   AntiXss.HtmlEncode:

原因如下:

      a.AntiXss Libaray 在不断地更新升级。

     b. 你永远不知道什么时候一种新的XSS攻击方法被人发现,采用白名单有效地防范未知的XSS攻击方式。

当然AntiXss.HtmlEncode的效率不如HttpUtility.HtmlEncode.但是这个效率的损失微不足道。

3)  调用GetSafeHtmlFragment / GetSafeHtml来消除html代码的有害部分

上面说了我是调用GetSafeHtmlFragement来消除代码中的有害部分原因如下:

   a.我用的是linq to sql 来做数据访问,仅仅需要几句代码就可以拦截所有的XSS请求。

   b.消除html 代码中的有害部分对莆田物流网没有什么影响。

下面是代码

    public void SubmitChanges()

    {

        Protect(this.Context.GetChangeSet().Inserts);

        Protect(this.Context.GetChangeSet().Updates);

 

        this.Context.SubmitChanges();

    }

 

    private static void Protect(IList<object> cs)

    {

        foreach (var io in cs)

        {

            Type type = io.GetType();

            PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance

                                                           | BindingFlags.Public);

 

            foreach (var p in properties)

            {

                if (!p.CanRead || !p.CanWrite) continue;

                if (p.PropertyType != typeof(string)) continue;

                object v = p.GetValue(io, null);

                if (v == null) continue;

 

                p.SetValue(io, Sanitizer.GetSafeHtmlFragment(v.ToString()), null);

            }

        }

    

 意思在在调用SubmitChanges之前,对于所有类型为string 的Property 的get方法调用GetSafeHtmlFragment. 

后记:这些方法我现在都已经采用在了莆田物流网上。

作者: 莆田物流网-0594wl 发表于 2011-04-04 14:07 原文链接

推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架