/*
利用 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>