小议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 原文链接