Web基于HTTP,是一个无状态的协议。它的每次请求都是新的且不会记录之前请求的数据,当外部浏览器开始发起请求后,IIS服务器会通过一个Http.sys的程序监听所有的HTTP请求并交给w3wp.exe进程处理,w3wp内部对请求的文件扩展名做筛选,如果请求的是html、css、js、jpg等静态文件,则直接将内容返回,如果是非静态文件,则会继续调用aspnet_isapi.dll文件进入.NET CLR,如图2-50所示。
从aspnet_isapi.dll开始内部会继续对.NET文件扩展名的请求做解析处理,先后调用ISAPIRunTime、HttpRuntime、HttpApplicationFactory、HttpApplication四个对象,关于这4个对象的介绍见表2-20。
图2-50 aspnet_isapi.dll处理.NET请求
表2-20 aspnet_isapi处理请求的对象
.NET Web应用的运行都离不开HttpModule和HttpHandler这两个对象,这两个对象处理HTTP请求最终都是通过IHttpHandler接口实现的,整个处理流程如图2-51所示。
.NET处理HTTP请求就像一个乘客带着行李乘坐高铁一样,HttpModule看成是中途停靠的各大高铁站,HttpHandler是高铁的终点站。
当HttpContext对象创建后,HttpRuntime将随即创建一个用于处理请求的对象,这个对象的类型为HttpApplication。在HttpApplication中,通过事件机制分解为多个独立的步骤,并且依次处理HTTP请求,这种处理机制称为管道。因此,通过编写事件处理方法就可以自定义每一个请求的扩展处理过程,.NET 4.0版本提供了19个标准事件,常用事件见表2-21。
图2-51 .NET处理HTTP请求管道
表2-21 .NET生命周期的常用事件
在.NET中,每个HTTP请求都会经过注册的IHttpModule,并最终指向一个IHttpHandler。因此,无论是使用WebForm还是MVC开发的Web应用都会经过管道中的模块。
IHttpHandler是一个可以让外部自定义实现的接口,其中ProcessRequest方法用来处理HTTP上下文的请求,创建一个自定义的类MyHttpHandler实现此接口,具体代码如下所示。
MyHttpHandler使用前需要在web.config文件中进行配置,具体可参考如下XML代码。
其中,verb表示请求的动作,如POST、GET、PUT等,如果是“*”表示全部动作均可用;path表示当请求路径匹配到*.aspx文件扩展名时,会执行MyHttpHandler;type表示MyHttpHandler的命名空间和类名。
HttpHandler在执行前会经过IHttpModule接口,此接口常用于自定义处理HTTP请求逻辑,如拦截或修改请求字段等。比如创建一个自定义的MyHttpModule类实现IHttpModule接口,可以清晰地看到HTTP请求生命周期中的各个事件和执行顺序,具体代码如下所示。
IHttpModule使用前也需要注册,注册的方法和IHttpHandler类似,同样在system.webServer节点下进行添加,使用modules元素,详细配置如下所示。
在.NET中,定义在System.Web命名控件下的IHttpModule接口专门用于定义HttpApp-lication对象的事件处理,实现了IHttpModule接口的类称为HttpModule,IHttpModule接口有个重要的Init方法,此方法用于注册HttpApplication对象的事件。例如,定义一个处理BeginRequest事件的HttpModule,具体代码如下所示。
这里注册的事件为context_BeginRequest,包括获取请求的URL和所有的请求体数据,代码如下所示。
接下来检查HTTP请求方法,如果是GET请求,会进一步检查查询字符串或表单数据,通过captureSqlInject方法检查是否存在SQL注入攻击,代码如下所示。
定义SQL注入规则变量sqlRule,用于匹配类似'or' '='这样的万能密码SQL注入攻击,captureSqlInject方法检查查询参数是否匹配SQL注入规则,规则内容如下所示。
如果HTTP请求中匹配了SQL注入攻击的规则,就会调用blockPage方法阻断当前请求的执行,先编译成名为van1ee-HWAF.dll文件,然后放置于站点目录下的bin文件夹,如图2-52所示。
还需要将HttpModule注册到网站配置文件web.config中才能真正生效,注册XML内容如下所示。
图2-52 HWAF.dll放置于bin目录下
通过浏览器发起/BookWebService.asmx?id=1%27or%27=%20%27or请求,运行后被拦截,如图2-53所示。
图2-53 HWAF.dll成功拦截SQL注入请求
外部请求到达.NET服务器时,为了处理请求,.NET会创建一个HttpRequest类型的对象用于获取请求的参数,经过服务端处理后会创建一个HttpResponse对象表示响应,并通过HttpServerUtility对象处理站点虚拟路径和服务器文件实际路径之间的映射关系。这些处理工作统一由HttpContext进行管理,HttpContext常用属性见表2-22。
表2-22 HttpContext常用属性
.NET通过Request封装了客户端请求信息,常用的3种取得数据的方法有Request.Form、Request.QueryString、Request,第三种是前两种的缩写,可以取代前两种方法。而前两种主要对应Form提交时的两种不同提交方法,分别是Post方法和Get方法。比如,新建一个RequestPage.aspx页面用于显示Request对象常用的属性,具体代码如下所示。
获取客户端发起的所有请求数据,包括只能在HTTP报文可见的属性,运行后的结果如图2-54所示。
图2-54 HttpRequest对象常用属性
.NET通过Response封装了服务端响应的信息,Response表示服务器响应对象。每当客户端发出一个请求时,服务器就会用一个响应对象来处理这个请求,处理完这个请求之后,服务器就会销毁这个响应对象,以便继续接受其他客户端请求。常用属性见表2-23。
表2-23 HttpResponse常用属性
.NET通过Server封装了服务端信息,Server对象用于获取服务器的相关信息的对象,常用属性见表2-24。
表2-24 HttpServerUtility常用属性