1.5 全局应用程序类Global.asax

Global. asax文件(也称全局应用程序类)是一个可选的文件,该文件包含响应ASP.NET或HTTP模块所引发的应用程序级别和会话级别事件的代码。Global.asax文件驻留在ASP.NET应用程序的根目录中,并且一个Web应用程序只能够有一个Global.asax文件。运行时,分析Global.asax并将其编译到一个动态生成的.NET Framework类,该类是从HttpApplication基类派生的。

Global. asax文件被配置为任何(通过URL的)直接HTTP请求都被自动拒绝,所以用户不能下载或查看其内容。ASP.NET页面框架能够自动识别出对Global.asax文件所做的任何更改。如果不定义该文件,ASP.NET页框架假设你未定义任何应用程序或会话事件处理程序。当你将更改保存到活动Global.asax文件时,ASP.NET页框架检测到该文件已被更改。它完成应用程序的所有当前请求,将Application_OnEnd事件发送到任何侦听器,并重新启动应用程序域。实际上,这会重新启动应用程序,关闭所有浏览器会话并刷新所有状态信息。当来自浏览器的下一个传入请求到达时,ASP.NET页框架将重新分析并重新编译Global.asax文件且引发Application_OnStart事件。所以只有在希望处理应用程序事件或会话事件时,才开始创建它。

要为你的Web应用程序添加一个Global.asax文件,请选择项目后右击鼠标,在弹出的快捷菜单里面选择“Add”|“New Item”命令后,会弹出一个模板选择窗体,在里面选择“Global Application Class”模板就可以了。在Visual Studio中加入Global.asax文件后,它里面包含了常用的应用程序事件的空事件处理程序,你只需要在相应的方法里加入自己的处理程序即可。

1.5.1 Global.asax的事件

Global. asax文件继承自HttpApplication类,它维护一个HttpApplication对象池,并在需要时将对象池中的对象分配给应用程序。Global.asax文件包含以下事件:

❑Application_Init:在应用程序被实例化或第一次被调用时,该事件被触发。对于所有的HttpApplication对象实例,它都会被调用。

❑Application_Disposed:在应用程序被销毁之前触发。这是清除以前所用资源的理想位置。

❑Application_Error:当应用程序中遇到一个未处理的异常时,该事件被触发。

❑Application_Start:在HttpApplication类的第一个实例被创建时,该事件被触发。它允许你创建可以由所有HttpApplication实例访问的对象。

❑Application_End:在HttpApplication类的最后一个实例被销毁时,该事件被触发。在一个应用程序的生命周期内它只被触发一次。

❑Application_BeginRequest:在接收到一个应用程序请求时触发。对于一个请求来说,它是第一个被触发的事件,请求一般是用户输入的一个页面请求((UL)。

❑Application_EndRequest:针对应用程序请求的最后一个事件。

❑Application_PreRequestHandlerExecute:在ASP.NET页面框架开始执行诸如页面或Web服务之类的事件处理程序之前,该事件被触发。

❑Application_PostRequestHandlerExecute:在ASP.NET页面框架结束执行一个事件处理程序时,该事件被触发。

❑Applcation_PreSendRequestHeaders:在ASP.NET页面框架发送HTTP头给请求客户(浏览器)时,该事件被触发。

❑Application_PreSendContent:在ASP.NET页面框架发送内容给请求客户(浏览器)时,该事件被触发。

❑Application_AcquireRequestState:在ASP.NET页面框架得到与当前请求相关的当前状态((Sssion状态)时,该事件被触发。

❑Application_ReleaseRequestState:在ASP.NET页面框架执行完所有的事件处理程序时,该事件被触发。这将导致所有的状态模块保存它们当前的状态数据。

❑Application_ResolveRequestCache:在ASP.NET页面框架完成一个授权请求时,该事件被触发。它允许缓存模块从缓存中为请求提供服务,从而绕过事件处理程序的执行。

❑Application_UpdateRequestCache:在ASP.NET页面框架完成事件处理程序的执行时,该事件被触发,从而使缓存模块存储响应数据,以供响应后续的请求时使用。

❑Application_AuthenticateRequest:在安全模块建立起当前用户的有效的身份时,该事件被触发。在这个时候,用户的凭据将会被验证。

❑Application_AuthorizeRequest:当安全模块确认一个用户可以访问资源之后,该事件被触发。

❑Session_Start:在一个新用户访问应用程序Web站点时,该事件被触发。

❑Session_End:在一个用户的会话超时、结束或他们离开应用程序Web站点时,该事件被触发。

其实,使用这些事件的一个关键问题是知道它们被触发的顺序,某些事件并不是每次请求都触发。Application_Init事件和Application_Start事件在应用程序第一次启动时被触发一次。相似地,Application_Disposed和Application_End事件在应用程序终止时被触发一次。此外,基于会话的事件((Sssion_Start和Session_End)只在用户进入和离开站点时被使用。其余的事件则处理应用程序请求,这些事件被触发的顺序是:

1)Application_BeginRequest.

2)Application_AuthenticateRequest.

3)Application_AuthorizeRequest.

4)Application_ResolveRequestCache.

5)在这个时候,请求被转交给合适的处理程序。

6)Application_AcquireRequestState.

7)Application_PreRequestHandlerExecute.

8)Application_PreSendRequestHeaders.

9)Application_PreSendRequestContent.

10)此时,适当的处理程序执行请求。

11)Application_PostRequestHandlerExecute.

12)Application_ReleaseRequestState.

13)Application_UpdateRequestCache.

14)Application_EndRequest.

1.5.2 在Global.asax文件里实现通用防SQL注入漏洞程序

相信大家都知道,SQL注入是黑客常用的Web攻击方法之一,如何有效地防SQL注入攻击是编写Web程序首先要考虑的。现在就来演示如何在Global.asax文件里实现通用防SQL注入漏洞程序。

首先,需要创建一个SQLInjectionHelper类完成恶意代码的检查,如代码清单1-11所示。

代码清单1-11 SQLInjectionHelper类


using System;

using System.Collections.Generic;

using System.Text;

using System.Text.RegularExpressions;

using System.Web;

namespace_1_3

{

public class SQLInjectionHelper

{

///<summary>

///获取Post的数据

///</summary>

public static bool ValidUrlData(string request)

{

bool result=false;

//获取Post的数据

if(request=="POST")

{

for(int i=0;i<HttpContext.Current.Request.Form.Count;i++)

{

result=ValidData(HttpContext.Current.Request.Form[i].ToString());

if(result)

{

break;

}

}

}

//获取QueryString中的数据

else

{

for(int i=0;i<HttpContext.Current.Request.QueryString.Count;i++)

{

result=ValidData(HttpContext.Current.Request.QueryString[i].ToString());

if(result)

{

break;

}

}

}

return result;

}

///<summary>

///验证是否存在注入代码

///</summary>

///<param name="inputData">输入字符</param>

private static bool ValidData(string inputData)

{

//验证inputData是否包含恶意集合

if(Regex.IsMatch(inputData, GetRegexString()))

{

return true;

}

else

{

return false;

}

}

///<summary>

///获取正则表达式

///</summary>

private static string GetRegexString()

{

//构造SQL的注入关键字符

string[]strBadChar={"and"

,"exec","insert","select","delete","update"

,"count","from","drop","asc","char","or"

,"%",";",":","\'","\"","-","chr"

,"mid","master","truncate","char","declare"

,"SiteName","net user","xp_cmdshell","/add"

,"exec master.dbo.xp_cmdshell","net localgroup administrators"};

//构造正则表达式

string str_Regex=".*(";

for(int i=0;i<strBadChar.Length-1;i++)

{

str_Regex+=strBadChar[i]+"|";

}

str_Regex+=strBadChar[strBadChar.Length-1]+").*";

return str_Regex;

}

}

}


有了这个类之后,就可以使用Global.asax中的Application_BeginRequest(object sender, EventArgs e)事件来实现表单或URL提交数据的获取,获取之后传给SQLInjectionHelper类publicstatic bool ValidUrlData(string request)方法来完成恶意代码的检查。见代码清单1-12。

代码清单1-12 Global.asax


//在接收到一个应用程序请求时触发。对于一个请求来说,它是第一个被触发的事件,请求一般是用户输入的一个页面请求((UL)。

protected void Application_BeginRequest(object sender, EventArgs e)

{

bool result=false;

result=SQLInjectionHelper.ValidUrlData(Request.RequestType.ToUpper());

if(result)

{

Response.Write("您提交的数据有恶意字符!");

Response.End();

}

}


到现在为止,一个通用防SQL注入漏洞程序已经基本完成。现在就来建一个测试页面做一下SQL注入测试,如代码清单1-13所示。

代码清单1-13 Test.aspx


<%@Page Language="C#"AutoEventWireup="true"CodeBehind="Test.aspx.cs"

Inherits="_1_3.Test"Keywords="sdfsd"%>

<!DOCTYPE html PUBLIC"-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head runat="server">

<title></title>

</head>

<body>

<form id="form1"runat="server">

<div>

<asp:TextBox ID="TextBox1"runat="server"></asp:TextBox>

</div>

<asp:Button ID="bt_Post"runat="server"Text="获取Post数据"onclick="bt_Post_Click"/>

<asp:Button ID="bt_Get"runat="server"Text="获取Get数据"onclick="bt_Get_Click"/>

</form>

</body>

</html>


如代码清单1-13所示,首先在页面创建一个TextBox来模拟用户的输入,然后分别添加“获取Post数据”和“获取Get数据”这两个Button来模拟Post请求和Get请求,请求事件的代码,如代码清单1-14所示。

代码清单1-14 Test.aspx.cs


protected void bt_Post_Click(object sender, EventArgs e)

{

}

protected void bt_Get_Click(object sender, EventArgs e)

{

Response.Redirect("Test.aspx?a=1&b=2&c=3");

}


创建完测试程序后,运行结果如图1-34所示。

如图1-34所示,只要在文本框中输入所定义的非法字符串,不论Post请求还是Get请求,都会被防SQL注入程序所截获,弹出如图1-35所示页面。

figure_0080_0054

图 1-34 测试防SQL注入程序的页面

figure_0080_0055

图 1-35 提示错误信息