/* 利用 HttpModule 统一干预、处理(例如: 过滤关键字) ASP.Net WebForm Control 的输出渲染 前几天在阅读老赵的《一个较完整的关键字过滤解决方案》上中下, http://www.cnblogs.com/JeffreyZhao/archive/2008/12/22/filter-forbidden-word-solution.html 当时提出了一个在 HttpModule "输出流"中转"字符串"后利用"替换",实现"基于输出干预处理"的过滤方案, 《HttpModule 实现 ASP.Net (*.aspx) 中文简繁体的自动转换,不用修改原有的任何代码,直接部署即可!》 http://microshaoft.cnblogs.com/archive/2005/12/03/289665.html 我也承认那个方案是有性能问题的。 最近在想一个实现全局解决"跨站脚本攻击"的统一通用干预处理,实现安全输出的方案。 "跨站脚本攻击"的一般解决方案就是在"输出"时,也就是先做"HTML/JavaScript Encode",然后输出 Safe Html/JavaScript。 ASP.Net WebControl 及其属性,有很多其实都不会自动 Encode 后输出的,即不是天然免疫 XSS Attack 的 《What's wrong with ASP.NET? HTML encoding》 http://msmvps.com/blogs/calinoiu/archive/2006/06/13/102957.aspx 《Which ASP.NET Controls Automatically Encodes?》 https://blogs.msdn.com/sfaust/archive/2008/09/02/which-asp-net-controls-automatically-encodes.aspx 《下面是一个很全的 "不安全控件及属性" 的 "黑名单"》 https://blogs.msdn.com/sfaust/attachment/8918996.ashx 我的方案目前还只是一个原型 就是只将 ASP.Net WebForm Sever WebControl/HtmlControl 的一些与"文本展现或输出"相关的属性统一处理的方案 目前在遍历所有控件的过程中,利用反射(性能)只处理了 System.Web.UI.WebControls 命名空间下的控件的"Text"属性 System.Web.UI.HtmlControls 命名空间下的控件的"Value"属性 发现天然能够干预处理程序代码动态 Add 的 Control 漏处理了其他命名的展现相关属性 而且还有一些过多处理了 WebForm Page 默认自动添加的控件的情况,因此还很不完善。 不能处理其他形式的 Response 输出(例如: Response.Write、前代码的<%= 后代码类成员变量%>), 自定义的 UserControl、WebCustomControl 的控件如果非"Text"或"Value"命名的展现属性也无法处理, 当然也有可能误伤与展现无关的"Text"或"Value"属性。 该方案逐步完善后,理论上,应该能"忽略"掉不必处理的控件及属性,而且还要按不安全"控件及其属性"的各种情况,分别处理,还是有一定的工作量。 另外性能尚未评估,遍历控件可能存在一定瓶颈, 其实我认为使用 HttpModule.dll、HttpHandler.dll、Global.asax 本身也存在一些性能瓶颈,因为所有的请求与输出都要流经此处。 以下完整代码 ControlsPropertyFilterHttpModule.cs web.config test.aspx (注意有XSS Attack 测试代码,不必惊慌只是 alert) */ //ControlsPropertyFilterHttpModule.cs namespace Microshaoft { using System; using System.Web; using System.Web.UI; using System.Reflection; public class ControlsPropertyFilterHttpModule : IHttpModule { private HttpApplication _contextApplication; public void Init(HttpApplication context) { _contextApplication = context; _contextApplication.PostMapRequestHandler += new EventHandler(_contextApplication_PostMapRequestHandlerProcess); } public void Dispose() { _contextApplication = null; _contextApplication.Dispose(); } public void _contextApplication_PostMapRequestHandlerProcess(object sender, EventArgs e) { IHttpHandler handler = null; if (_contextApplication == null) { return; } if (_contextApplication.Context.Handler is Page) { handler = _contextApplication.Context.Handler; } if (handler != null) { Page page = handler as Page; //page.PreRender += new EventHandler(page_PreRender); page.PreRenderComplete += new EventHandler(page_PreRender); } } private void page_PreRender(object sender, EventArgs e) { Page page = sender as Page; ControlCollection cc = page.Controls; RecursiveProcessControls(cc); } private static void RecursiveProcessControls(ControlCollection cc) { foreach (Control c in cc) { Type t = c.GetType(); //需要按控件种类分情况处理各种文本显示相关的属性 //目前只处理 Text 和 Value 属性 PropertyInfo pi = t.GetProperty("Text"); //Server WebControls if (pi != null) { string s = (string) (pi.GetValue(c, null)); s = string.Format("Microshaoft处理了[{0}]", s); //s = HttpUtility.HtmlEncode(s); //AntiXSS pi.SetValue(c, s, null); } pi = t.GetProperty("Value"); //Server HtmlControls if (pi != null) { string s = (string) (pi.GetValue(c, null)); s = string.Format("Microshaoft处理了[{0}]", s); //s = HttpUtility.HtmlEncode(s); //AntiXSS pi.SetValue(c, s, null); } if (c.HasControls()) { RecursiveProcessControls(c.Controls); } } } } }
//test.aspx <%@ Page language="c#" AutoEventWireup ="true"%> <%@ Import Namespace="System.Data" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" > <HTML> <HEAD> <title>WebForm1</title> <meta name="generator" content="editplus" /> <meta name="author" content="" /> <meta name="keywords" content="" /> <meta name="description" content="" /> <script language="C#" runat="server"> protected void Page_Load(object sender, EventArgs ea) { h1.Text += "<script>alert('HL Xss Attack')" + "</scr" + "ipt>"; DataTable dt = MakeTable("F1","F2"); string expression = "1 = 1 or f1 = '2'"; DataView dv = dt.DefaultView; dv.Sort = "f1 desc"; dv.RowFilter = expression; datagrid1.DataSource = dv; datagrid1.DataBind(); gridview1.DataSource = dv; gridview1.DataBind(); TextBox tb = new TextBox(); tb.Text = "动态 TextBox"; p1.Controls.Add(tb); } void datagrid1_ItemDataBound(object sender, DataGridItemEventArgs e) { /// foreach (TableCell cell in e.Item.Cells) /// { /// if (cell.Text != string.Empty) /// { /// cell.Text = HttpUtility.HtmlEncode(cell.Text); /// } /// } } void gridview1_RowDataBound(object sender, GridViewRowEventArgs e) { /// foreach (TableCell cell in e.Row.Cells) /// { /// if (cell.Text != string.Empty) /// { /// cell.Text = HttpUtility.HtmlEncode(cell.Text); /// } /// } } private static DataTable MakeTable ( string c1Name , string c2Name ) { DataTable table= new DataTable(); DataColumn column = new DataColumn(c1Name, typeof(int)); table.Columns.Add(column); column = new DataColumn(c2Name, typeof(string)); table.Columns.Add(column); table.Rows.Add(1,"<script>alert('datagrid xss attack')</scr" + "ipt>"); table.Rows.Add(2, "\u003c" + "scr" + "ipt\u003ealert\u0028\u0022gridview XSS \u0041ttack\u0022\u0029\u003c/script\u003e"); return table; } </script> </HEAD> <body MS_POSITIONING="GridLayout"> <form id="Form1" method="post" runat="server"> <asp:TextBox ID="tb1" Text="静态 textBox" runat="server" /> <asp:Label ID="l1" Text="静态 label" runat="server" /> <asp:Panel id="p1" runat="server"/> <asp:Hyperlink ID="h1" NavigateUrl="http://www.baidu.com" runat="server"> 百度 Hyperlink<script>alert('HL Xss Attack')</script> </asp:Hyperlink> <input ID="Value2" Type="Text" Value="静态 HtmlControls HtmlInputText" runat="server"/> <asp:ListBox ID="lb1" Width="" runat="server"> <asp:ListItem><script>alert('LB Xss Attack')</script></asp:ListItem> <asp:ListItem></asp:ListItem> </asp:ListBox> <ASP:DataGrid ID="datagrid1" runat="server" AutoGenerateColumns="True" OnItemDataBound = "datagrid1_ItemDataBound" /> <ASP:GridView ID="gridview1" runat="server" AutoGenerateColumns="True" OnRowDataBound = "gridview1_RowDataBound" /> </form> </body> </HTML>