必威-必威-欢迎您

必威,必威官网企业自成立以来,以策略先行,经营致胜,管理为本的商,业推广理念,一步一个脚印发展成为同类企业中经营范围最广,在行业内颇具影响力的企业。

用户(Member)的讲解时必威:,ASP.NET页面与IIS底层

2019-09-20 17:23 来源:未知

0x01 前言

在渗透测试的时候各种PHP版的一句话木马已经琳琅满目,而.NET平台下的一句话木马则百年不变,最常见的当属下面这句

必威 1

必威 2

笔者感觉有必要挖坑一下.NET平台里的一句话木马,经过一番摸索填坑终于可以总结出了.NET下的三驾马车,于是乎有了这个系列的文章。今天是第一篇着重介绍一般处理程序 下的工作原理和如何实现一句话木马的介绍,当然介绍之前笔者找到了一款ashx马儿

必威 3

这个马儿已经实现了菜刀可连,可用,还是挺棒的,但因为体积过大,并且在服务端实现了大多数功能,其实更像是一个大马,只是对客户端的菜刀做了适配可用,所以不能说是一句话木马了,至于要打造一款居家旅行必备的菜刀马,还得从原理上搞清楚 ashx的运行过程。

 

Asp.Net构架(Http请求处理流程) - Part.1

ASP.NET页面与IIS底层交互和工作原理详解 

HTTP、Asp.net管道与IIS

0x02 简介

从Asp.Net 2.0开始,Asp.Net提供了称为一般处理程序的处理程序,允许我们使用比较简单的方式定义扩展名为ashx的专用处理程序。对于Asp.Net应用来说,网站最快的处理结果就是HTML网页,生成网页的工作通常使用扩展名为Aspx的Web窗体来完成。对于处理结果不是HTML的请求,都可以通过一般处理程序完成。例如生成RSS Feed、XML、图片等。 一般处理程序是Asp.Net应用中最为简单、高效的处理程序,在处理返回类型不是HTML的请求中有着重要的作用。通常是实现IHttpHandler接口,因为不必继承自Page类,所以没有那么多事件需要处理,不必消耗太多资源,所以性能方面要比Aspx高。

当Http请求进入 Asp.Net Runtime以后,它的管道由托管模块(NOTE:Managed Modules)和处理程序(NOTE:Handlers)组成,并且由管道来处理这个 Http请求。

必威 4

HttpRuntime将Http请求转交给 HttpApplication,HttpApplication代表着程序员创建的Web应用程序。HttpApplication创建针对此Http请求的 HttpContext对象,这些对象包含了关于此请求的诸多其他对象,主要是HttpRequest、HttpResponse、HttpSessionState等。这些对象在程序中可以通过Page类或者Context类进行访问,而接下来的一句话木马就是通过Context类进行请求交互的。

前言:最近一段时间在学习MVC源码,说实话,研读源码真是一个痛苦的过程,好多晦涩的语法搞得人晕晕乎乎。这两天算是理解了一小部分,这里转载微信公共号DotNet中一篇文章,给自己提个醒。

引言

第一回:

 

吴剑 2010-04-19

0x03 一句话的实现

 

 

引言

我查阅过不少Asp.Net的书籍,发现大多数作者都是站在一个比较高的层次上讲解Asp.Net。他们耐心、细致地告诉你如何一步步拖放控件、设置控件属性、编写CodeBehind代码,以实现某个特定的功能。

这种做法,实际上是回答了“如何去做”的问题,却没有回答“为什么可以这样做”的问题。

尽管我很推崇 悉江华 先生的《圣殿祭祀的Asp.Net开发详解》一书,但当我翻看了一下其对角色(Role) 和 用户(Member)的讲解时,我决定跳过去直接读后面的章节。因为我发现他也随了大流,对这部分的讲解停留在“如何去做”的层面上。我相信像悉先生 这样的牛人是不可能不了解底层运作原理的,仅仅是因为那本书原本就已经很厚了吧。

当你按“如何去做”所讲解的内容去开发程序的时候,对于你的用户,你仍是一名程序员;但对于实现了MembershipProvider 和 RoleProvider 抽象类的微软开发人员来说,你已经成了他们的一个用户。

NOTE:我既不反对一些作者只讲解“如何去做”,也不反对你只学“如何去做”,这样也有它的好处,就是可以快速开发。我只是建议多掌握一点底层知识,对一些问题会有更好的理解。

希望通过这一系列文章的讲解,可以让你更好的理解Asp.Net的运作原理和做以了解。

原创文章,转载必需注明出处:

3.1、同步处理:IHttpHandler

首先可以打开C:WINDOWSMicrosoft.NETFrameworkv4.0.30319CONFIG 目录下的web.config 文件,找到httpHandlers结点,应该可以看到如下这样的代码

必威 5

.Net Framework在处理Http请求时的所采用的默认Handler。而如果我们要用编程的方式来操控一个Http请求,我们就需要实现IHttpHandler接口,来定制我们自己的需求。IHttpHandler的定义是这样的:

必威 6

由上面可以看出IHttpHandler要求实现一个方法和一个属性。其中 ProcessRequest,从名字看就知道这里应该放置我们处理请求的主要代码。IsReusable属性,MSDN上是这样解释的:获取一个值,该值指示其他请求是否可以使用 IHttpHandler 实例。也就是说后继的Http请求是不是可以继续使用实现了该接口的类的实例。如果返回true,则HttpHandler能得到重用,或许某些场合下,是可以达到性能优化的目的。但是,它也可能会引发新的问题:HttpHandler实例的一些状态会影响后续的请求,也正是由于这个原因在默认情况下,都是不重用的。在通常情况下,当实现IsReusable时返回false,虽然性能上不是最优,但却是最安全的做法。

了解了基本原理后,笔者开始手动打造一句话小马,这个马儿要和PHP或者同胞兄弟Aspx一样,仅仅在服务端存放体积很小的一段代码,参考Aspx一句话木马的实现原理,发现是基于Jscript.Net语言中的eval方法去执行任意字符串的,所以首当其冲考虑用Jscript,并且需要实现IhttpHandler这个接口,查询资料后得到在Jscript.Net和VB.Net中均采用implements去实现,最终写出一句话木马服务端代码:

必威 7

这里有必要简单的介绍一下Jscript.Net的语法;和大多数语言类似导入命名空间也是通过Import,以下摘自微软描述

必威 8

必威 9

script简单语法就介绍到这里,更多的语法可参考微软官方文档:)

万事俱备,打开浏览器输入 context.Response.Write(DateTime.Now.ToString 成功打印出当前时间

必威 10

一、MVC原理解析

 

最近园子里Asp.Net Core火了一阵,不管微软的开源动作有多么迟缓,还是希望微软能够给力一次。作为Core的主要Web框架——MVC,虽然已经开源,但是读起来着实费劲,并且感觉很多核心部件都找不到。

 

于是只能通过Reflector去反编译MVC5的组件以及参考博客园Fish Li等大神的文章去自己理解了。

 

还是给出MVC的开源地址:

我查阅过不少Asp.Net的书籍,发现大多数作者都是站在一个比较高的层次上讲解Asp.Net。他们耐心、细致地告诉你如何一步步拖放控件、设置控件属性、编写CodeBehind代码,以实现某个特定的功能。

Http请求处理流程概述

思考“为什么在地址栏输入www.tracefact.net就可以看到张子阳的个人空间?”,类似于思考“为什么苹果是往地上掉不是往天上飘?”。对于普通访问者来说,这就像每天太阳东边升起西边落下一样是理所当然的;对于很多程序员来说,认为这个与己无关,不过是系统管理员或者网管员的责任。毕竟,IIS是 Windows 的一个组件,又不是 Asp.Net 的一个组成部分。而实际上,从你轻拍回车到页面呈现在你眼前的十分之一秒内,IIS和.Net Framework已经做了大量的幕后工作。

你可能觉得了解这些幕后工作是如何运作的无关紧要,作为程序员的你只要保证开发出的程序可以高效地运行就可以了。然而,在开发过程中,你却发现常常需要使用诸如 HttpContext 这样的类。这个时候,你可曾思考过这些类的构成和类的实体是如何创建的?你可能简单地回答:HttpContext代表当前请求的一个上下文环境。可你又知道IIS 、Framework、Asp.Net 是如何协同工作处理每个Http请求、如何区分不同的请求、IIS、Framework、Asp.Net三者之间的数据如何流动么?

回答上面这些问题,首先需要了解IIS是如何处理页面请求的,这也是理解 Form验证模式和Windows 验证模式 的基础。

吴剑

3.2、异步处理:IHttpAsyncHandler

在ASP.NET程序中,适当地使用异步是可以提高服务端吞吐量的。 这里所说的适当地使用异步,一般是说:当服务器的压力不大且很多处理请求的执行过程被阻塞在各种I/O等待操作上时, 而采用异步来减少阻塞工作线程的一种替代同步调用的方法。 反之,如果服务器的压力已经足够大,或者没有发生各种I/O等待,那么,在此情况下使用异步是没有意义的。那么在HttpHandler的接口里要想支持异步,则必须使用另一个接口:IhttpAsyncHandler

必威 11

这个接口也很简单只有二个方法,在.net中,异步都是建立在IAsyncResult接口之上的,而BeginProcessRequest / EndProcessRequest是对这个接口最直接的使用方式。笔者通过创建一个C#的Demo来演示异步处理的过程

必威 12

值得注意的是ProcessRequest方法和IsReusable属性可以不实现它们,但必须要保留下来,因为这个方法也是接口的一部分。核心方法是BeginProcessRequest,其中参数asyncCallback是一个内部委托,那么就需要定义一个委托,将来通过异步的方式回调自定义的方法writeFile 来写入文件。知道原理后就开始着手打造异步调用的一句话木马,和IhttpHandler一样需要通过Jscript.Net的eval方法去实现代码执行,有点遗憾之处笔者查询资料后发现Jscript.Net暂时不支持委托类型,不过只需要在BeginProcessRequest方法里增加HttpContext.Current.Response.End();就可以实现功能并且不让程序抛出异常,实现的代码如下:

必威 13

打开浏览器,测试效果如下

必威 14

 

这种做法,实际上是回答了“如何去做”的问题,却没有回答“为什么可以这样做”的问题。

Http请求刚刚到达服务器的时候

当服务器接收到一个 Http请求的时候,IIS 首先需要决定如何去处理这个请求(NOTE:服务器处理一个.htm页面和一个.aspx页面肯定是不一样的么)。那IIS依据什么去处理呢?―― 根据文件的后缀名。

服务器获取所请求的页面(NOTE:也可以是文件,比如 jimmy.jpg)的后缀名以后,接下来会在服务器端寻找可以处理这类后缀名的应用程序,如果IIS找不到可以处理此类文件的应用程序,并且这个文件也没有受到服务器端的保护(NOTE:一个受保护的例子就是 App_Code中的文件,一个不受保护的例子就是你的js脚本),那么IIS将直接把这个文件返还给客户端。

能够处理各种后缀名的应用程序,通常被称为 ISAPI 应用程序(NOTE:Internet Server Application Programe Interface,互联网服务器应用程序接口)。虽然这 ISAPI 听上去还挺气派,也算是“应用程序”呢,但仔细看看它的全称就明白了:它实际上只是一个接口,起到一个代理的作用,它的主要工作是映射所请求的页面(文件)  和与此后缀名相对应的实际的处理程序。

让我们更进一步地看一下 ISAPI ,看看它到底是什么样子,请按下面的步骤进行:

  1. 打开IIS。
  2. 选择随意一个站点,鼠标右键,“属性”。
  3. 选择“主目录”选项卡。
  4. 选择“配置”。

你应该会看到如下的画面:

图1. 应用程序配置

必威 15

很清楚地就可以看到,所有IIS所能处理,或者叫 ISAPI 所提供代理服务的 文件类型 及其相对应的实际的后台处理程序都在这里清楚地列出来了。

我们找到 .aspx 的应用处理程序,然后点“编辑”,会出现下面的画面:

图2. 编辑.aspx文件的处理程序

必威 16

 

一路看到这里,可以看出,所有的.aspx文件实际上都是由 aspnet_isapi.dll 这个程序来处理的,当IIS把对于.aspx页面的请求提交给了aspnet_isapi.dll以后,它就不再关心这个请求随后是如何处理的了。现在我们应该知道:Asp.Net 只是服务器(IIS)的一个组成部分而已,它是一个 ISAPI扩展。

这里需要注意两点:

  • 当你修改“限制为”后,可以限制页面(文件)只能以某种特定方式访问
  • “确认文件是否存在”是实现 URL 地址映射的关键选项,我以后会专门讲述。

前言

0X04 菜刀连接

圈内常说武功再高,也怕菜刀;那么就有必要了解一下菜刀在连接ASPX的时候会发送什么数据了,经过抓包得到下图的请求

必威 17

对于.NET平台的应用程序默认连接后发送的可执行字符串是Response.Write,而这样的输出需要继承的对象是Page类,所以至今为止,在菜刀的层面.NET下仅支持ASPX,再来看一般处理程序中已经继承了HttpContext对象实例化后的变量context,由此可以构造出

必威 18

修改好后用菜刀连接成功,如下图

必威 19

基于优化考虑将HandlerSpy.ashx进一步压缩体积后只有531字节,而AsyncHandlerSpy.ashx也才719字节。

必威 20

1、MVC原理

 

之前的文章有介绍MVC的路由机制,其实路由机制算是MVC的原理的核心之一。在此我们还是要不厌其烦再来谈谈整个过程,因为这是理解MVC原理不可逾越的鸿沟。当我们收到一个URL的请求时,服务端收到请求,主要经历以下几个步骤:

 

 

  1. 请求被UrlRoutingModule部件拦截

     

  2. 封装请求上下文HttpContext,成为HttpContextWrapper对象。

     

  3. 根据当前的HttpContext,从Routes集合中得到与当前请求URL相符合的RouteData对象。

     

  4. 将RouteData与HttpContext请求封装成一个RequestContext对象。

     

  5. 根据RequestContext对象,从RouteData的RouteHandler中获取IHttpHandler(MVC里面会有一个IHttpHandler的实现类MvcHandler)。

     

  6. 执行IHttpHandler(MvcHandler),然后就是通过反射激活具体的controller,执行具体的action。

 

附上一张大致的流程图:

 

必威 21

 

纵观整个过程,看上去很复杂,各种对象缠绕,看得人晕晕的。其实如果你静下心来仔细研读MVC的源码你会发现其实并没有想像中的那般复杂,请有点耐心听博主慢慢道来。

 

1、整个过程有两个核心的组件,文中博主用红色标记了出来:UrlRoutingModuleMvcHandler,上文提到的各个过程都和两个组件有紧密的联系。而这两个组件分别继承至IHttpModule和IHttpHandler接口,熟悉Asp.net管线事件的朋友应该会记得这两个接口,在管道事件里面这两个接口扮演着重要角色。要理解MVC的上述原理,必须要先理解这两类接口的原理以及使用。

 

2、UrlRoutingModule的作用可以理解为通过一系列的与路由相关的组件去解析当前请求的Controller与Action名称,其实简单点理解,比如我们请求

 

3、MvcHandler的作用就更加直接,上述通过拦截组件得到了请求的Controller和Action的名称,MvcHandler组件将当前请求的Controller名称反射得到对应的控制器对象,然后执行对应的Action方法。比如还是上述

 

4、综上,联合这两个组件来理解,UrlRoutingMudule组件的主要作用是解析当前的Controller与Action名称,MvcHandler的作用是将得到的Controller名称激活,得到具体的Controller对象,然后执行对应的Action方法。

 

所以,要理解MVC的原理,必须要了解这两个组件的基本原理以及作用。下面就根据这两个组件分别展开说明,相信理解了下面的内容,你对mvc的原理会有一个新的认识。

 

尽管我很推崇 悉江华 先生的《圣殿祭祀的Asp.Net开发详解》一书,但当我翻看了一下其对角色(Role) 和 用户(Member)的讲解时,我决定跳过去直接读后面的章节。因为我发现他也随了大流,对这部分的讲解停留在“如何去做”的层面上。我相信像悉先生 这样的牛人是不可能不了解底层运作原理的,仅仅是因为那本书原本就已经很厚了吧。

理解宿主环境(Hosting)

从本质上讲,Asp.Net 主要是由一系列的类组成,这些类的主要目的就是将Http请求转变为对客户端的响应。HttpRuntime类是Asp.Net的一个主要入口,它有一个称作 ProcessRequest 的方法,这个方法以一个 HttpWorkerRequest 类作为参数。HttpRuntime 类几乎包含着关于单个 Http请求的所有信息:所请求的文件、服务器端变量、QueryString、Http 头信息 等等。Asp.Net 使用这些信息来加载、运行正确的文件,并且将这个请求转换到输出流中,一般来说,也就是HTML页面。

NOTE:二般来说,也可以是张图片。

当 Web.config文件的内容发生改变 或者 .aspx文件发生变动的时候,为了能够卸载运行在同一个进程中的应用程序(NOTE:卸载也是为了重新加载),Http请求被分放在相互隔离的应用程序域中。

NOTE:可能你以前就听过应用程序域,但是不了解怎么回事,应用程序域就是 AppDomain。

对于IIS来说,它依赖一个叫做 HTTP.SYS 的内置驱动程序来监听来自外部的 HTTP请求。在操作系统启动的时候,IIS首先在HTTP.SYS中注册自己的虚拟路径。

NOTE:实际上相当于告诉HTTP.SYS哪些URL是可以访问的,哪些是不可以访问的。举个简单的例子:为什么你访问不存在的文件会出现 404 错误呢?就是在这一步确定的。

如果请求的是一个可访问的URL,HTTP.SYS会将这个请求交给 IIS 工作者进程。

NOTE:IIS6.0中叫做 w3wp.exe,IIS5.0中叫做 aspnet_wp.exe。

每个工作者进程都有一个身份标识 以及 一系列的可选性能参数。

NOTE:可选性能参数,是指诸如 回收机制的设置、超时时间设置 等等。

接下来进行的事情就是上一章节讲述的 ISAPI 了。

NOTE:这部分的内容相关性比较强,为了让大家好理解,我最后还是决定把 ISAPI 放到前面了,可能全系列完成的时候会再调整吧。

除了映射文件与其对应的处理程序以外,ISAPI 还需要做一些其他的工作:

  1. 从HTTP.SYS中获取当前的Httq请求信息,并且将这些信息保存到 HttpWorkerRequest 类中。
  2. 在相互隔离的应用程序域AppDomain中加载HttpRuntime。
  3. 调用 HttpRuntime的ProcessRequest方法。

接下来才是程序员通常编写的代码所完成的工作了,然后,IIS 接收返回的数据流,并重新返还给 HTTP.SYS,最后,HTTP.SYS 再将这些数据返回给客户端浏览器。

OK,现在你看到张子阳的空间主页了。

图3.Asp.Net 的宿主环境

必威 22

本文介绍了IIS、Http管道、Asp.Net管道一些相对较底层知识,个人能力有限,不足之处请及时指正。

0x05 防御措施

通过菜刀连接的方式,添加可以检测菜刀关键特征的规则;对于Web应用来说,尽量保证代码的安全性;

二、HttpHandler

 

上文说过MvcHandler是继承至IHttpHandler接口的!为什么这里大标题会用HttpHandler而不是MvcHandler呢?

 

因为博主觉得,HttpHandler实在是太重要了,首先得理解了HttpHandler这么一个大的东西,然后再来看具体的MvcHandler才有意义。

 

当你按“如何去做”所讲解的内容去开发程序的时候,对于你的用户,你仍是一名程序员;但对于实现了MembershipProvider 和 RoleProvider 抽象类的微软开发人员来说,你已经成了他们的一个用户。

理解管道(Pipeline)

在前面两章中,我们在一个相对比较低的层次上讨论了从发出Http请求到看到浏览器输出这转瞬即逝的十分之一秒内IIS和 Framework 所做的事情。但是我们忽略了一个细节:程序员编写的代码是如何在这一过程中衔接的,本章我们就来看看这个问题。

当Http请求进入 Asp.Net Runtime以后,它的管道由托管模块(NOTE:Managed Modules)和处理程序(NOTE:Handlers)组成,并且由管道来处理这个 Http请求。

图4. 理解 Http 管道

必威 23

我们按编号来看一下这幅图中的数据是如何流动的。

  1. HttpRuntime将Http请求转交给 HttpApplication,HttpApplication代表着程序员创建的Web应用程序。HttpApplication创建针对此Http请求的 HttpContext对象,这些对象包含了关于此请求的诸多其他对象,主要是HttpRequest、HttpResponse、HttpSessionState等。这些对象在程序中可以通过Page类或者Context类进行访问。、

2. 接下来Http请求通过一系列Module,这些Module对Http请求具有完全的控制权。这些Module可以做一些执行某个实际工作前的事情

3. Http请求经过所有的Module之后,它会被HttpHandler处理。在这一步,执行实际的一些操作,通常也就是.aspx页面所完成的业务逻辑。可能你会觉得在创建.aspx页面并没有体会到这一过程,但是,你一定知道,.aspx 页面继承自Page类,我们看一下Page类的签名:

public class Page : TemplateControl, IHttpHandler{
    // 代码省略
}

可以看到,Page类实现了IHttpHandler接口,HttpHandler也是Http请求处理的最底层。

4.HttpHandler处理完以后,Http请求再一次回到Module,此时Module可以做一些某个工作已经完成了之后的事情。

NOTE:注意我用红色标识的字,然后回想一下:Asp.Net 中是不是有众多的 Inserting 、Inserted 之类成对的事件?其实,这里讲述的就是为什么Asp.Net可以将一个Insert操作分成前后两部分,然后再分别进行事件拦截的幕后原理。

如果我们将注意力只集中在Http请求、HttpHandler和HttpModule上,不去考虑HttpContext和HttpApplication,那么图4.可以简化成下面这样:

图5.Http请求在HttpHandler 和 HttpModule 中的流动方向

必威 24

吴剑

0x06 小结

文章中不足之处在于Jscript异步处理的时候没有能够用委托的方式去调用,这是一个遗憾,如果有同学提出了更好的解决方法,欢迎多多交流;还有本文提供了两种方式实现ashx一句话的思路,当然还有更多编写一句话的技巧有待发掘,下次将介绍另外一种姿势,敬请期待;文章的代码片段请点这里

1、HttpHandler、IHttpHandler、MvcHandler的说明

 

  • HttpHandler指所有实现IHttpHandler接口一类类型的统称,它是一个大的称谓。这些类型有一个共同的功能,那就是可以用来处理Http请求。

     

  • IHttpHandler是微软定义的一类接口,用来约束所有能够处理Http请求的类型的接口规则。

     

  • MvcHandler是Mvc里面实现IHttpHandler接口的类型,也就是说,MvcHandler是Mvc里面处理Http请求的类型。

 

总而言之,HttpHandler只是一个逻辑称谓,它并不具体存在。而IHttpHandler和MvcHandler是.net framework里面具体存在的接口和实现类,是前者的表现形式。

NOTE:我既不反对一些作者只讲解“如何去做”,也不反对你只学“如何去做”,这样也有它的好处,就是可以快速开发。我只是建议多掌握一点底层知识,对一些问题会有更好的理解。

总结

本文中,我首先概要介绍了这系列文章将要为大家讲述的主题。然后,我提出了部分程序员存在的一个问题:在一个比较高的层次上学习和使用Asp.Net。

随后,我以一个访问我个人空间首页的例子,引出了本文主要讲述的三个内容:

  1. Http请求刚刚到达时IIS时,IIS 所做的工作。
  2. Http请求的宿主环境。
  3. Http管道。

希望这篇文章能给你带来帮助。

HTTP管道

0x07 参考链接

 

希望通过这一系列文章的讲解,可以让你更好的理解Asp.Net的运作原理和做以了解。

第二回:

ISAPI

2、IHttpHandler解析

 

Http请求处理流程概述

思考“为什么在地址栏输入www.tracefact.net就可以看到张子阳的个人空间?”,类似于思考“为什么苹果是往地上掉不是往天上飘?”。对于普通访问者来说,这就像每天太阳东边升起西边落下一样是理所当然的;对于很多程序员来说,认为这个与己无关,不过是系统管理员或者网管员的责任。毕竟,IIS是 Windows 的一个组件,又不是 Asp.Net 的一个组成部分。而实际上,从你轻拍回车到页面呈现在你眼前的十分之一秒内,IIS和.Net Framework已经做了大量的幕后工作。

你可能觉得了解这些幕后工作是如何运作的无关紧要,作为程序员的你只要保证开发出的程序可以高效地运行就可以了。然而,在开发过程中,你却发现常常需要使用诸如 HttpContext 这样的类。这个时候,你可曾思考过这些类的构成和类的实体是如何创建的?你可能简单地回答:HttpContext代表当前请求的一个上下文环境。可你又知道IIS 、Framework、Asp.Net 是如何协同工作处理每个Http请求、如何区分不同的请求、IIS、Framework、Asp.Net三者之间的数据如何流动么?

回答上面这些问题,首先需要了解IIS是如何处理页面请求的,这也是理解 Form验证模式和Windows 验证模式 的基础。

引言

在 Part.1 Http请求处理流程 一文中,我们了解了Http请求的处理过程以及其它一些运作原理。我们知道Http管道中有两个可用接口,一个是IHttpHandler,一个是IHttpModule,但在Part.1中,我并没有详细讲述如何对它们进行编程,只是轻描淡写地一笔带过。所谓学以致用,前面已经介绍了不少概念和原理。在本文中,我们通过几个范例来了解 IHttpHandler,看看掌握这些原理的实际用途。

当用户在浏览器中键入一个URL、点击一个超链接或提交一个HTML表单,在服务器端,IIS5或IIS6将会收到这个请求,并根据请求URL的扩展名不同交由不同的ISAPI扩展来处理,如下图所示:

2.1、Asp.net管线事件简易说明

 

做过Webform开发的园友应该记得,在asp.net的页面生命周期里面,一共有24个管线事件,完整的管线事件可参考MSDN文档:

 

在处理该请求时将由 HttpApplication 类执行以下事件。 希望扩展 HttpApplication 类的开发人员尤其需要注意这些事件。

1. 对请求进行验证,将检查浏览器发送的信息,并确定其是否包含潜在恶意标记。 有关更多信息,请参见 ValidateRequest 和脚本侵入概述。

  1. 如果已在 Web.config 文件的 UrlMappingsSection 节中配置了任何 URL,则执行 URL 映射。

  2. 引发 BeginRequest 事件。

  3. 引发 AuthenticateRequest 事件。

  4. 引发 PostAuthenticateRequest 事件。

  5. 引发 AuthorizeRequest 事件。

  6. 引发 PostAuthorizeRequest 事件。

  7. 引发 ResolveRequestCache 事件。

  8. 引发 PostResolveRequestCache 事件。

  9. 根据所请求资源的文件扩展名(在应用程序的配置文件中映射),选择实现 IHttpHandler 的类,对请求进行处理。 如果该请求针对从 Page 类派生的对象(页),并且需要对该页进行编译,则 ASP.NET 会在创建该页的实例之前对其进行编译。

  10. 引发 PostMapRequestHandler 事件。

  11. 引发 AcquireRequestState 事件。

  12. 引发 PostAcquireRequestState 事件。

  13. 引发 PreRequestHandlerExecute 事件。

  14. 为该请求调用合适的 IHttpHandler 类的 ProcessRequest 方法(或异步版 IHttpAsyncHandler.BeginProcessRequest)。 例如,如果该请求针对某页,则当前的页实例将处理该请求。 

  15. 引发 PostRequestHandlerExecute 事件。

  16. 引发 ReleaseRequestState 事件。

  17. 引发 PostReleaseRequestState 事件。

  18. 如果定义了 Filter 属性,则执行响应筛选。

  19. 引发 UpdateRequestCache 事件。

  20. 引发 PostUpdateRequestCache 事件。

  21. 引发 EndRequest 事件。

  22. 引发 PreSendRequestHeaders 事件。

  23. 引发 PreSendRequestContent 事件。

 

这里不可能把每个管线事件将清楚,但是在整个管线事件中,有两个重要的角色就是HttpHandler和HttpModule。在这些事件中,第10个事件【根据所请求资源的文件扩展名(在应用程序的配置文件中映射),选择实现 IHttpHandler 的类,对请求进行处理】 是HttpHandler创建的地方。

 

关于WebForm里面HttpHandler创建的详细过程,这里就不展开说了,如果有兴趣可以参考

 

Http请求刚刚到达服务器的时候

当服务器接收到一个 Http请求的时候,IIS 首先需要决定如何去处理这个请求(NOTE:服务器处理一个.htm页面和一个.aspx页面肯定是不一样的么)。那IIS依据什么去处理呢?―― 根据文件的后缀名。

服务器获取所请求的页面(NOTE:也可以是文件,比如 jimmy.jpg)的后缀名以后,接下来会在服务器端寻找可以处理这类后缀名的应用程序,如果IIS找不到可以处理此类文件的应用程序,并且这个文件也没有受到服务器端的保护(NOTE:一个受保护的例子就是 App_Code中的文件,一个不受保护的例子就是你的js脚本),那么IIS将直接把这个文件返还给客户端。

能够处理各种后缀名的应用程序,通常被称为 ISAPI 应用程序(NOTE:Internet Server Application Programe Interface,互联网服务器应用程序接口)。虽然这 ISAPI 听上去还挺气派,也算是“应用程序”呢,但仔细看看它的全称就明白了:它实际上只是一个接口,起到一个代理的作用,它的主要工作是映射所请求的页面(文件) 和与此后缀名相对应的实际的处理程序。

让我们更进一步地看一下 ISAPI ,看看它到底是什么样子,请按下面的步骤进行:

  1. 打开IIS。
  2. 选择随意一个站点,鼠标右键,“属性”。
  3. 选择“主目录”选项卡。
  4. 选择“配置”。

你应该会看到如下的画面:

图1. 应用程序配置

必威 25

很清楚地就可以看到,所有IIS所能处理,或者叫 ISAPI 所提供代理服务的 文件类型 及其相对应的实际的后台处理程序都在这里清楚地列出来了。

我们找到 .aspx 的应用处理程序,然后点“编辑”,会出现下面的画面:

图2. 编辑.aspx文件的处理程序

必威 26

 

一路看到这里,可以看出,所有的.aspx文件实际上都是由 aspnet_isapi.dll 这个程序来处理的,当IIS把对于.aspx页面的请求提交给了aspnet_isapi.dll以后,它就不再关心这个请求随后是如何处理的了。现在我们应该知道:Asp.Net 只是服务器(IIS)的一个组成部分而已,它是一个 ISAPI扩展。

这里需要注意两点:

  • 当你修改“限制为”后,可以限制页面(文件)只能以某种特定方式访问
  • “确认文件是否存在”是实现 URL 地址映射的关键选项,我以后会专门讲述。

IHttpHandler 概述

可能和我一样,很多Asp.Net开发人员都有过Asp的背景,以至于我们在开发程序的时候,通常都是在“页面级”上思考,也就是说我们现在正在做的这个页面应该有什么样的功能,是进行一个问卷调查还是一个数据库查询等等。而很少在“请求级”思考,考虑有没有办法来通过编码的方式来操控一个Http请求。

实际上,Framework提供了一系列的接口和类,允许你对于Http请求进行编程,而实现这一操作的一个主要的接口,就是 IHttpHandler(另一个是IHttpModule)。

应该还记得第一节中我们提到过 ISAPI,它根据文件名后缀把不同的请求转交给不同的处理程序。但是仔细看看就会发现:几乎一大半的文件都交给 aspnet_isapi.dll 去处理了。很明显,aspnet_isapi.dll 不可能对每种文件采用同一种方式处理,那么 aspnet_isapi.dll 是如何更进一步处理不同的文件,交由谁去处理呢?为了搞清楚这个问题,我们需要打开机器上C:WINDOWSMicrosoft.NETFrameworkv2.0.50727CONFIG 目录下的web.config 文件。

NOTE:我查阅了很多资料,都说是在 machine.config 中,但实际上 v2.0.50727 下的machine.config中httpHandlers结点是这样的:<httpHandlers />,并没有给出详细的处理程序,在Web.config中才能看到。而v1.1.4322 下的machine.config中却有。

找到httpHandlers结点,应该可以看到如下这样的代码(做了省略):

<httpHandlers>
... ... //略
<add path="*.axd" verb="*" type="System.Web.HttpNotFoundHandler" validate="True" /><add path="*.aspx" verb="*" type="System.Web.UI.PageHandlerFactory" validate="True" />
   <add path="*.ashx" verb="*" type="System.Web.UI.SimpleHandlerFactory" validate="True" />
   <add path="*.asax" verb="*" type="System.Web.HttpForbiddenHandler" validate="True" />
<add path="*.ascx" verb="*" type="System.Web.HttpForbiddenHandler" validate="True" />
   <add path="*.config" verb="*" type="System.Web.HttpForbiddenHandler" validate="True" />
   <add path="*.cs" verb="*" type="System.Web.HttpForbiddenHandler" validate="True" />
   <add path="*" verb="GET,HEAD,POST" type="System.Web.DefaultHttpHandler" validate="True" />
   ... ... //略
</httpHandlers>

可以看到,在<httpHandlers>结点中将不同的文件类型映射给不同的Handler去处理,对于.aspx来说,是由System.Web.UI.PageHandlerFactory来处理。而对于.cs来说,是由System.Web.HttpForbiddenHandler 处理,从ForbiddenHandler名字中出现的Forbidden (翻译过来是“禁止”)可以看出,这个Handler可以避免我们的源码被看到。

NOTE:System.Web.UI.PageHandlerFactory 是一个IHttpHandlerFactory,而不是一个单一的HttpHandler,IHttpHandlerFactory用来做什么后面会说明。

上面列出的是.Net Framework在处理Http请求时的所采用的默认Handler。而如果我们要用编程的方式来操控一个Http请求,我们就需要实现IHttpHandler接口,来定制我们自己的需求。

IHttpHandler的定义是这样的:

public interface IHttpHandler{
    void ProcessRequest(HttpContext context);
    bool IsReusable { get; }
}

由上面可以看出IHttpHandler要求实现一个方法和一个属性。其中 ProcessRequest,从名字(处理请求)看就知道这里应该放置我们处理请求的主要代码。

IsReusable属性,MSDN上是这样解释的:获取一个值,该值指示其他请求是否可以使用 IHttpHandler 实例。也就是说后继的Http请求是不是可以继续使用实现了该接口的类的实例,一般来说,我把它设置成true。

那么实现此接口的类形式应该是这样的:

public class CustomHandler : IHttpHandler{
    public void ProcessRequest(HttpContext context)  {
       // 处理请求的代码
    }
    public bool IsReusable {
       get { return true; }
    }
}

而为了能使用这个自定义的HttpHandler,我们需要在应用程序目录下的Web.config中注册它。

 <system.web>
    <httpHandlers>
      <add path="*.jpg" verb="*" type="MyNameSpace.MyClass, MyDllName" />
    </httpHandlers>
 </system.web>

应该发现这与之前在C:WINDOWSMicrosoft.NETFrameworkv2.0.50727CONFIG目录下web.config中看到的几乎完全一样。这里,path指的是请求的文件名称,可以使用通配符扩大范围,也可以明确指定这个handler仅用于处理某个特定的文件(比如说:filename.aspx)的请求。verb指的是请求此文件的方式,可以是post或get,用*代表所有访问方式。type属性由“,”分隔成两部分,第一部分是实现了接口的类名,第二部分是位于Bin目录下的编译过的程序集名称。

NOTE:如果你新建一个项目,并且在项目下创建HandlerTest.cs,然后让站点引用该项目,那么在生成解决方案的时候会自动将编译好的.dll文件添到Bin目录中。
    NOTE:MyDll只写程序集名,不要加后面的.dll。

必威 27

TAG标签:
版权声明:本文由必威发布于必威-编程,转载请注明出处:用户(Member)的讲解时必威:,ASP.NET页面与IIS底层