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所示页面。
图 1-34 测试防SQL注入程序的页面
图 1-35 提示错误信息