小议asp.net中 防范XSS
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 原文链接