初识.Net审计

初识.Net审计

前言

对.net认知比较少,学习一下.net的一些简单审计。遇到.net源码能简单审审。

基础概念

文件类型

ASPX.cs是页面后的代码,aspx负责显示,服务器端的动作就是在aspx.cs定义的。
.cs是类文件,公共类
.ashx是一般处理程序,主要用于写web handler,可以理解成不会显示的aspx页面,不过效率更高
dll就是cs文件编译之后的程序集

aspx:

Aspx是浏览器直接访问的页面,对应web page。有iis处理成html内容输出

ascx:

Ascx 是定义的Web的用户控件(UserControl),要插入aspx页面呈现.头部文件<%Control…%>声明为控件文件,用户控件继承自System.Web.UI.UserControl

ashx:

Ashx是一个专门用于处理http请求(HttpRequest)和修改(HttpResponse)响应(handling HttpRequests and modifying HttpResponses)的文件类型,用来处理自定义的Http请求,可以在web.config定义运行时针对ashx的Http请求处理方式、

<add verb="*" path="*.ashx" type="namespace.class,assembly" validate="false"/>

这样我们就可以用assemly文件中的namespace下的class对应的类来处理ashx的http请求了,对http内容进行特别的处理。

从而免去了普通aspx页面的控件解析和页面处理的过程。比如特别适合生成动态图片、添加特别的动态文本等内容,给图片添加水印,登录检查。

asmx:

asms 是web服务文件,asmx.cs里有相关代码,属于B/S形式,用SOAP协议方式Http访问,用XML返回,可以返回基础类型和public结果类型。

ASP.net使用asmx文件来对WebServices的支持。

编程模式

Web Forms 是三种创建 ASP.NET 网站和 Web 应用程序的编程模式中的一种。

其他两种编程模式是 Web Pages 和 MVC(Model View Controller 模型-视图-控制器)。

WebConfig配置

web.config是一个XML文件,用来储存Asp.net Web应用程序的配置信息,包括数据库连接字符、身份安全验证等,可以出现在Asp.net Web应用程序服务器上的任何目录中,每个Web.config将配置设置应用到它所在的目录及虚拟子目录下,子目录中的设置可以随意重写或修改在父目录中指定的设置。该文件不需要重启服务就可以生效。

<system.web>

<httpHandlers>
<add verb="*" path="*.js.axd" type="Prolliance.ADManager.Web.ScriptTranslator" />
</httpHandlers>

</system.web>

<system.webServer>

<httpHandlers>
<add verb="*" path="*.js.axd" type="Prolliance.ADManager.Web.ScriptTranslator" />
</httpHandlers>

</system.webServer>

verb:表示访问方式如get,post,*表示任何方式

path:表示文件名称或以某种后缀结尾的文件

type:表示访问path文件时的处理类的名称空间完整路径

system.webServer 节中的某些设置只适用于 IIS 7.0 集成模式,而不适用于经典模式。具体而言,如果应用程序正在经典模式下运行,则会忽略 Web.config 文件的 system.WebServer 节中指定的所有托管代码模块和处理程序。与 IIS 的早期版本相同,托管代码模块和处理程序必须在 system.web 节的 httpModules 和 httpHandlers 元素中定义

注意如果IIS使用.net4.0以上版本的框架,<system.web>中的httpHandlers节点就没有用了,而应该使用微软专为4.0以上版本设计的新节点
<system.webServer>来配置ashx的handlers

标签

它的根节点为<configuration>,该节点下包含常见的子节点有:<configSections><appSettings><connectionStrings>(保存数据库连接字符串)、<location><system.web>

configSections

configSections 元素指定了配置节和处理程序声明。由于 ASP.NET 不对如何处理配置文件内的设置作任何假设,因此这非常必要。但 ASP.NET 会将配置数据的处理委托给配置节处理程序。配置结构信息如下

<configSections>

<!--定义配置节处理程序与配置元素之间的关联。-->

<section />

<!--定义配置节处理程序与配置节之间的关联。-->

<sectionGroup />

<!--移除对继承的节和节组的引用。-->

<remove />

<!--移除对继承的节和节组的所有引用,只允许由当前 section 和 sectionGroup 元素添加的节和节组。-->

<clear/>

</configSections>

每个 section 元素标识一个配置节或元素以及对该配置节或元素进行处理的关联 ConfigurationSection 派生类。可以在 sectionGroup 元素中对 section 元素进行逻辑分组,以对 section 元素进行组织并避免命名冲突。section 和 sectionGroup 元素包含在 configSections 元素中。

如果配置文件中包含 configSections 元素,则 configSections 元素必须是 configuration 元素的第一个子元素。

下面我们来示例写一个自定义配置信息,并完成它的SectionHandler,首先我们在<configuration>节点下添加configSections

<configuration>

<configSections>

<sectionGroup name="mySectionGroup">

<section name="mySection" requirePermission="true"

type="ConfigTest.SectionHandler.MySectionHandler,ConfigTest.SectionHandler" />

</sectionGroup>

</configSections>

<mySectionGroup>

<mySection>

<add key="key1" value="value1" />

<add key="key2" value="value2" />

<add key="key3" value="value3" />

<add key="key4" value="value4" />

<add key="key5" value="value5" />

</mySection>

</mySectionGroup>

<system.web>

<compilation debug="true" targetFramework="4.0" />

</system.web>

</configuration>

编写自定义SectionHandler,我们为MySectionHandler返回一个Hashtable的数据

namespace ConfigTest.SectionHandler

{

public class MySectionHandler : IConfigurationSectionHandler

{

public object Create(object parent, object configContext, System.Xml.XmlNode section)

{

Hashtable ht = new Hashtable();

foreach (XmlNode node in section.ChildNodes)

{

if (node.Name == "add")

{

ht.Add(node.Attributes["key"].Value, node.Attributes["value"].Value);
}
}
return ht;
}
}
}

appSettings

<appSettings>

<!--图片类型扩展名-->

<add key="ImgType" value=".bmp;.jpg;.gif;.png"/>

</appSettings>

调用方法为:

string ImgType = ConfigurationManager.AppSettings["ImgType"];

connectionStrings

connectionStrings和appSettings类似,不过用于保存配置数据库连接信息,下面给一个实例。

<connectionStrings>

<add name="SqlserverConnStr" connectionString="Data Source=Aron1;Initial Catalog= pubs;UserId=sa;Password=asdasd;"/>

<add name="OrcleConnStr" connectionString="Provider=msdaora;Data Source= MyOracleDB;UserId=UserName;Password=asdasd;"/>

</connectionStrings>

调用方式为:

string connStr = ConfigurationManager.ConnectionStrings["SqlserverConnStr"].ConnectionString;

authentication

下面的代码示例演示如何为基于窗体的身份验证配置站点、指定传输来自客户端的登录信息的 Cookie 的名称以及指定当初始身份验证失败时使用的登录页的名称。必须将 authorization 节包含在内才能要求对所有用户进行 Forms 身份验证,并拒绝匿名用户访问站点。

  1. Windows(默认)

将 Windows 验证指定为默认的身份验证模式。将它与以下任意形式的 Microsoft Internet 信息服务 (IIS) 身份验证结合起来使用:基本、摘要、集成 Windows 身份验证 (NTLM/Kerberos) 或证书。在这种情况下,您的应用程序将身份验证责任委托给基础 IIS。

  1. Forms

将 ASP.NET 基于窗体的身份验证指定为默认身份验证模式。

  1. Passport

将 Microsoft Passport Network 身份验证指定为默认身份验证模式。

  1. None

不指定任何身份验证。您的应用程序仅期待匿名用户,否则它将提供自己的身份验证。

下面的代码示例演示如何为基于窗体的身份验证配置站点、指定传输来自客户端的登录信息的 Cookie 的名称以及指定当初始身份验证失败时使用的登录页的名称。必须将 authorization 节包含在内才能要求对所有用户进行 Forms 身份验证,并拒绝匿名用户访问站点。

<configuration>

<system.web>

<authentication mode="Forms">

<forms name="401kApp" loginUrl="/login.aspx"/>

</authentication>

<authorization>

<deny users="?"/>

</authorization>

</system.web>

</configuration>

Login.aspx中登陆通过:

FormsAuthentication.RedirectFromLoginPage(this.TextBox1.Text, true);

httpHandlers:

HttpHandlers可用于根据请求中指定的 URL 和 HTTP 谓词将传入的请求映射到相应的处理程序。可以针对某个特定的目录下指定的特殊文件进行特殊处理。

下面我们来针对网站path目录下的所有*.abc文件夹来编写自定义HttpHandle。

定义一个类

namespace ConfigTest.HttpHandler

{
public class AbcHttpHandler : IHttpHandler, IRequiresSessionState
{
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
context.Response.Write("<h1><b>Hello HttpHandler</b></h1>");
context.Session["Test"] = "你在调用AbcHttpHandler容器中调用Session";
context.Response.Write(context.Session["Test"]);
}
}
}

我们还可以使用HttpHandlerFactory来进行handler自行切换。我们先定义两个HttpHandler,分别是httpHandler1和httpHandler2。然后定义一个继承于IHttpHandlerFactory的MyHandlerFactory来动态切换httpHandler

namespace ConfigTest.HttpHandler

{
public class MyHandlerFactory : IHttpHandlerFactory
{
public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
{
if (url.IndexOf("1") > -1)

{

return new HttpHandler1();

}

else if (url.IndexOf("2") > -1)

{

return new HttpHandler2();

}

//返回默认Handler

return context.Handler;

}

public void ReleaseHandler(IHttpHandler handler)

{

// throw new NotImplementedException();

}

}
================================================================================================================================

    
    public class HttpHandler1 : IHttpHandler, IRequiresSessionState

{

public bool IsReusable

{

get { return true; }

}

public void ProcessRequest(HttpContext context)

{

context.Response.Write("<h1>HttpHandler1</h1>");

}

}

public class HttpHandler2 : IHttpHandler, IRequiresSessionState

{

public bool IsReusable

{

get { return true; }

}

public void ProcessRequest(HttpContext context)

{

context.Response.Write("<h1>HttpHandler2</h1>");

}

}

}

我们设定url中存在1这个字符时用HttpHandler1,存在2这个字符里用HttpHandler2,否则返回系统默认的Handler。我们还得增加配置项

<httpHandlers>

<add path="path/*.abc" verb="*" type="ConfigTest.HttpHandler.AbcHttpHandler,ConfigTest.HttpHandler"/>

<add path="HandlerFactory/*.*" verb="*" type="ConfigTest.HttpHandler.MyHandlerFactory,ConfigTest.HttpHandler"/>

</httpHandlers>

httpModules

当请求在管道中传递时,HttpApplicaion对象中一系列的事件被触发.我们已经看到这些事件在Global.asax中作为事件被发布.这种方法是特定于应用程序的,可能并不总是你想要的.如果你要建立一个通用的可用被插入任何Web应用程序的HttpApplication事件钩子,你可用使用HttpModule,这是可复用的,不需要特定语应用程序代码的,只需要web.config中的一个条目.

<httpModules>

<add name="MyHttpModule" type="ConfigTest.HttpModule.MyHttpModule,ConfigTest.HttpModule"/>

</httpModules>

和HttpHandler一样,编写继承于IHttpModule的HttpModule:

namespace ConfigTest.HttpModule

{

public class MyHttpModule:IHttpModule

{

public void Dispose()

{

throw new NotImplementedException();

}

public void Init(HttpApplication context)

{

context.BeginRequest += new EventHandler(context_BeginRequest);

}

void context_BeginRequest(object sender, EventArgs e)

{

HttpApplication application = (HttpApplication)sender;

HttpContext context = application.Context;

context.Response.Write("Add BeginRequest by MyHttpModule!");

}

}

}

.NET MVC

路由工作原理

Asp.Net是一个管道模型,一个Http请求先经过HttpModule,再通过HttpHandlerFactory,创建一个对应的HttpHandler处理对应的请求。所以对Asp.Net的所有的扩展也是通过注册这些管道事件来实现的。因为路由是建立在Asp.Net Framework之上的,所以路由也是注册实现了管道事件。但是是通过注册HttpModulePostResolveRequestCache事件来实现的。

不直接注册HttpHandler来实现的原因是因为

  • HttpHandler多用来处理响应处理。

  • HttpModule多用来处理通用性和响应内容无关的功能。

    路由就是一个实现了IHttpModule接口的UrlRoutingModuleHttpModule,在管道事件中拦截请求,分析Url,匹配路由,再交给HttpHandler处理的过程。

解析流程

  1. 根据HttpContext,路由匹配规则,匹配一个RouteData对象。
  2. 调用RouteData对象的RouteHandler获取IRouteHandlerMVCRouteHandler
  3. 由匹配的RouteDataHttpContext创建RequestContext
  4. 由2的MVCRouteHandler和3的RequestContext创建IHttpHandler-MVCHandler.
  5. HttpHandler管道事件执行。

配置路由

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");//忽略该模式的URL

        routes.MapRoute(
            name: "Default",//路由名称
            url: "{controller}/{action}/{id}",//路由模板
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }//路由默认值,参数id可以为空
        );
    }
}
  • name:为该路由名称
  • url:为路由模板,{}是占位符。
  • defaults:为路由默认值

Global.asaxMVCApplication继承HttpApplication。而HttpApplication则是管理整个管道周期的实例。在该类中通过注册事件,或方法可以在管道事件中被调用。注册路由到应用程序就是在Application_Start()方法中实现。

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);//路由注册到应用程序
        BundleConfig.RegisterBundles(BundleTable.Bundles);
    }
}

过滤器

Filter 类型 实现的接口 描述
Authorization IAuthorizationFilter 最先运行的Filter,被用作请求权限校验
Action IActionFilter 在Action运行的前、后运行
Exception IExceptionFilter 当异常发生的时候运行

IActionFilter

public class SampleActionFilter:IActionFilter
    {
        public void OnActionExecuting(ActionExecutingContext context)
        {
            //操作执行前做的事情
        }
        public void OnActionExecuted(ActionExecutedContext context)
        {
            //操作执行后做的事情
        }
    }

AuthorizationFilterAttribute简单鉴权例子

public class AuthFilterAttribute : AuthorizationFilterAttribute
    {
        public override void OnAuthorization(HttpActionContext actionContext)
        {
            //如果用户方位的Action带有AllowAnonymousAttribute,则不进行授权验证
            if (actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any())
            {
                return;
            }
            var verifyResult = actionContext.Request.Headers.Authorization!=null &&  //要求请求中需要带有Authorization头
                               actionContext.Request.Headers.Authorization.Parameter == "123456"; //并且Authorization参数为123456则验证通过

            if (!verifyResult)
            {
                //如果验证不通过,则返回401错误,并且Body中写入错误原因
                actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.Unauthorized,new HttpError("Token 不正确"));
            }
        }
    }

App_Start\WebApiConfig.cs,在Register方法下加入Filter实例

public static void Register(HttpConfiguration config)
{
     config.MapHttpAttributeRoutes();
    //注册全局Filter
     config.Filters.Add(new AuthFilterAttribute());

     config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
}

Global.asax

验证一般都是在 global.asax 中

执行顺序

1.BeginRequest

2.AuthenticateRequest

3.AuthorizeRequest

4.ResolveRequestCache

5.AcquireRequestState

6.PreRequestHandlerExecute

7.PostRequestHandlerExecute

8.ReleaseRequestState

9.UpdateRequestCache

10.EndRequest

Global方法的含义

Application_Init:在每一个HttpApplication实例初始化的时候执行
Application_Disposed:在每一个HttpApplication实例被销毁之前执行
Application_Error:所有没有处理的错误都会导致这个方法的执行
Application_Start:在程序初始化的时候执行。在Web应用程序的生命周期里就执行一次,这里只能放一些公用的信息,比如HttpApplicationState。
Application_End:应用程序结束时,在最后一个HttpApplication销毁之后执行。对应Application_Start,在整个生命周期里面也是只执行一次。
Session_Start:会话开始时执行。
Session_End:会话结束或过期时执行。
Application_BeginRequest:BeginRequest是在收到Request时第一个触发的事件,这个方法第一个执行。
Application_AuthenticateRequest:当安全模块已经建立了当前用户的标识后执行。
Application_AuthorizeRequest:当安全模块已经验证了当前用户的授权时执行。
Application_ResolveRequestCache:当ASP.NET完成授权事件以使缓存模块从缓存中为请求提供服务时发生,从而跳过处理程序(页面或者是WebService)的执行。这样做可以改善网站的性能,这个事件还可以用来判断正文是不是从Cache中得到的。
Application_AcquireRequestState:当ASP.NET获取当前请求所关联的当前状态(如Session)时执行。
Application_PreRequestHandlerExecute:当ASP.Net即将把请求发送到处理程序对象(页面或者是WebService)之前执行。这个时候,Session就可以用了。
Application_PostRequestHandlerExecute:当处理程序对象工作完成后执行。
Application_ReleaseRequestState:在ASP.NET执行完所有请求处理程序后执行。ReleaseRequestState事件将使当前状态数据被保存。
Application_UpdateRequestCache:在ASP.NET执行完处理程序后为了后续的请求而更新响应缓存时执行。
Application_EndRequest:同上,EndRequest是在响应Request时最后一个触发的事件,这个方法自然就是最后一个执行的了。
Application_PreSendRequestHeaders:向客户端发送Http标头之前执行。
Application_PreSendRequestContent:向客户端发送Http正文之前执行。

.NET 解析过程

ASP.NET 请求处理过程是基于管道模型的,这个管道模型是由多个HttpModule和HttpHandler组成,ASP.NET 把http请求依次传递给管道中各个HttpModule,最终被HttpHandler处理,处理完成后,再次经过管道中的HTTP模块,把结果返回给客户端。我们可以在每个HttpModule中都可以干预请求的处理过程。

注意:在http请求的处理过程中,只能调用一个HttpHandler,但可以调用多个HttpModule。
当请求到达HttpModule的时候,系统还没有对这个请求真正处理,但是我们可以在这个请求传递到处理中心(HttpHandler)之前附加一些其它信息,或者截获的这个请求并作一些额外的工作,也或者终止请求等。在HttpHandler处理完请求之后,我们可以再在相应的HttpModule中把请求处理的结果进行再次加工返回客户端。

.NET对请求处理的过程:

当请求一个*.aspx文件的时候,这个请求会被inetinfo.exe进程截获,它判断文件的后缀(aspx)之后,将这个请求转交给 ASPNET_ISAPI.dll,ASPNET_ISAPI.dll会通过http管道(Http PipeLine)将请求发送给ASPNET_WP.exe进程,在ASPNET_WP.exe进程中通过HttpRuntime来处理这个请求,处理完毕将结果返回客户端。
inetinfo.exe进程:是www服务的进程,IIS服务和ASPNET_ISAPI.DLL都寄存在此进程中。
ASPNET_ISAPI.DLL:是处理.aspx文件的win32组件。其实IIS服务器是只能识别.html文件的,当IIS服务器发现被请求的文件是.aspx文件时,IIS服务器将其交给aspnet_isapi.dll来处理。
aspnet_wp.exe进程:ASP.NET框架进程,提供.net运行的托管环境,.net的CLR(公共语言运行时)就是寄存在此进程中。

ASP.NET Framework处理一个Http Request的流程:
HttpRequest-->inetinfo.exe-->ASPNET_ISAPI.dll-->ASPNET_WP.exe-->HttpRuntime-->HttpApplication Factory-->HttpApplication-->HttpModule-->HttpHandler Factory-->HttpHandler-->HttpHandler.ProcessRequest()

HttpModule

当请求到达HttpModule的时候,系统还没有对这个请求真正处理,但是我们可以在这个请求传递到处理中心(HttpHandler)之前附加一些其它信息,或者截获的这个请求并作一些额外的工作,也或者终止请求等。在HttpHandler处理完请求之后,我们可以再在相应的HttpModule中把请求处理的结果进行再次加工返回客户端。

HttpModule
    HTTP模块是实现了System.Web.IhttpModule接口的类。
    IHttpModule接口的声明:
        public interface IHttpModule
        {
            void Init (HttpApplication context);
            void Dispose ();
        }

**Init 方法:系统初始化的时候自动调用,这个方法允许HTTP模块向HttpApplication 对象中的事件注册自己的事件处理程序。

** Dispose方法: 这个方法给予HTTP模块在对象被垃圾收集之前执行清理的机会。此方法一般无需编写代码。

HTTP模块可以向System.Web.HttpApplication对象注册下面一系列事件:
AcquireRequestState 当ASP.NET运行时准备好接收当前HTTP请求的对话状态的时候引发这个事件。
AuthenticateRequest 当ASP.NET 运行时准备验证用户身份的时候引发这个事件。
AuthorizeRequest 当ASP.NET运行时准备授权用户访问资源的时候引发这个事件。
BeginRequest 当ASP.NET运行时接收到新的HTTP请求的时候引发这个事件。
Disposed 当ASP.NET完成HTTP请求的处理过程时引发这个事件。
EndRequest 把响应内容发送到客户端之前引发这个事件。
Error 在处理HTTP请求的过程中出现未处理异常的时候引发这个事件。
PostRequestHandlerExecute 在HTTP处理程序结束执行的时候引发这个事件。
PreRequestHandlerExecute 在ASP.NET开始执行HTTP请求的处理程序之前引发这个事件。在这个事件之后,ASP.NET 把该请求转发给适当的HTTP处理程序。
PreSendRequestContent 在ASP.NET把响应内容发送到客户端之前引发这个事件。这个事件允许我们在内容到达客户端之前改变响应内容。我们可以使用这个事件给页面输出添加用于所有页面的内容。例如通用菜单、头信息或脚信息。
PreSendRequestHeaders 在ASP.NET把HTTP响应头信息发送给客户端之前引发这个事件。在头信息到达客户端之前,这个事件允许我们改变它的内容。我们可以使用这个事件在头信息中添加cookie和自定义数据。
ReleaseRequestState 当ASP.NET结束所搜有的请求处理程序执行的时候引发这个事件。
ResolveRequestCache 我们引发这个事件来决定是否可以使用从输出缓冲返回的内容来结束请求。这依赖于Web应用程序的输出缓冲时怎样设置的。
UpdateRequestCache 当ASP.NET完成了当前的HTTP请求的处理,并且输出内容已经准备好添加给输出缓冲的时候,引发这个事件。这依赖于Web应用程序的输出缓冲是如何设置的。

HttpModule生命周期示意图:

BeginRequest和PreRequestHandlerExecute之间的事件是在服务器执行HttpHandler处理之前触发。
PostRequestHandlerExecute和PreSendRequestContent之间的事件是在服务器执行Handler处理之后触发。

第一步:创建一个类库ClassLibrary831。

第二步:在Init事件中注册EndRequest事件,并实现事件处理方法

  class TestModule:IHttpModule
                {
                    public void Dispose(){}
                    public void Init(HttpApplication context)
                    {
                        context.EndRequest += new EventHandler(context_EndRequest);
                    }
                    void context_EndRequest(object sender, EventArgs e)
                    {
                        HttpApplication ha = (HttpApplication)sender;
                        ha.Response.Write("<!--这是每个页面都会动态生成的文字。--grayworm-->");
                    }
                }

第三步:在Init事件中注册EndRequest事件,并实现事件处理方法

<httpModules>
     <add name="TestModule" type="ClassLibrary831.TestModule,ClassLibrary831">	   </add>
     </httpModules>

​ name:模块名称,一般是类名
​ type:有两部分组成,前半部分是命名空间和类名组成的全名,后半部分是程序集名称,如果类是直接放在App_Code文件夹中,那程序名称是App_Code。
​ 这样在Web站点是添加该类库的引用后,运行每个页面,会发现其源文件中都会加入

<!--这是每个页面都会动态生成的文字。 -->

这句话。同样的方法你也可以在其中加入JS代码。

IHttpModule权限认证

比较大的程序中,这种做法实在是太笨拙,因为你几乎要在每一个页面中都加入检测Session的代码,导致难以开发和维护。下面我们看看如何使用HttpModule来减少我们的工作量
由于在这里我们要用到Session中的内容,我们只能在AcquireRequestState和PreRequestHandlerExecute事件中编写代码,因为在HttpModule中只有这两事件中可以访问Session。

第一步:创建一个类库ClassLibrary831。

第二步:在Init事件中注册PreRequestHandlerExecute事件,并实现事件处理方法

  class AuthenticModule:IHttpModule
                {
                    public void Dispose(){}
                    public void Init(HttpApplication context)
                    {
                        context.PreRequestHandlerExecute += new EventHandler(context_PreRequestHandlerExecute);
                    }
                    void context_PreRequestHandlerExecute(object sender, EventArgs e)
                    {
                        HttpApplication ha = (HttpApplication)sender;
                        string path = ha.Context.Request.Url.ToString();
                        int n = path.ToLower().IndexOf("Login.aspx");
                        if (n == -1) //是否是登录页面,不是登录页面的话则进入{}
                        {
                            if (ha.Context.Session["user"] == null) //是否Session中有用户名,若是空的话,转向登录页。
                            {
                                ha.Context.Response.Redirect("Login.aspx?source=" + path);
                            }
                        }
                    }
                }

第三步:在Login.aspx页面的“登录”按钮中加入下面代码

       protected void Button1_Click(object sender, EventArgs e)
                {
                    if(true)    //判断用户名密码是否正确
                    {
                        if (Request.QueryString["source"] != null)
                        {
                            string s = Request.QueryString["source"].ToLower().ToString();   //取出从哪个页面转来的
                            Session["user"] = txtUID.Text;
                            Response.Redirect(s); //转到用户想去的页面
                        }
                        else
                        {
                            Response.Redirect("main.aspx");    //默认转向main.aspx
                        }
                    }
                }

第四步:在Web.Conofig中注册一下这个HttpModule模块

<httpModules>
           <add name="TestModule" type="ClassLibrary831.TestModule,ClassLibrary831"></add>
          </httpModules>

多模块的操作

如果定义了多个HttpModule,在web.config文件中引入自定义HttpModule的顺序就决定了多个自定义HttpModule在处理一个HTTP请求的接管顺序。

HttpHandler

HttpHandler是HTTP请求的处理中心,真正地对客户端请求的服务器页面做出编译和执行,并将处理过后的信息附加在HTTP请求信息流中再次返回到HttpModule中。
HttpHandler与HttpModule不同,一旦定义了自己的HttpHandler类,那么它对系统的HttpHandler的关系将是“覆盖”关系。
IHttpHandler接口声明

public interface IHttpHandler
    {
        bool IsReusable { get; }
        public void ProcessRequest(HttpContext context); //请求处理函数
    }

实例代码:

 class TestHandler : IHttpHandler
        {
            public void ProcessRequest(HttpContext context)
            {
                FileStream fs = new FileStream(context.Server.MapPath("worm.jpg"), FileMode.Open);
                byte[] b = new byte[fs.Length];
                fs.Read(b, 0, (int)fs.Length);
                fs.Close();
                context.Response.OutputStream.Write(b, 0, b.Length);
            }
            public bool IsReusable
            {
                get
                {
                    return true;
                }
            }
        }

web.config配置文件

  <httpHandlers>
       <add verb="*" path="*" type="ClassLibrary831.TestHandler,ClassLibrary831"></add>
      </httpHandlers>

Verb属性:指定了处理程序支持的HTTP动作。支持所有的HTTP动作;"GET"-支持Get操作;"POST"-支持Post操作;"GET, POST-支持两种操作。
Path属性:指定了需要调用处理程序的路径和文件名(可以包含通配符)。""、"*.aspx"、"showImage.aspx"、"test1.aspx,test2.aspx"
Type属性:用名字空间、类名称和程序集名称的组合形式指定处理程序或处理程序工厂的实际类型。ASP.NET运行时首先搜索bin目录中的DLL,接着在GAC中搜索。
这样程序运行的效果是该网站的任何一个页面都会显示worm.jpg图片。如何只让一个页面(default21.aspx)执行HttpHandler 中的ProcessRequest方法呢?最简单的办法是在Web.Config文件中把path配置信息设为default21.aspx。

IHttpHandler工厂

IHttpHandlerFactory的作用是对IHttpHandler进行管理。

IHttpHandlerFactory接口的声明:

 public interface IHttpHandlerFactory
        {
            IHttpHandler GetHandler (HttpContext context,string requestType,string url,string pathTranslated);
            void ReleaseHandler (IHttpHandler handler);
        }

GetHandler返回实现IHttpHandler接口的类的实例,ReleaseHandler使工厂可以重用现有的处理程序实例。
示例:两个用IHttpHandlerFactory来实现对不同HttpHandler的调用。
有两个HttpHandler:将图片显示在页面上的HttpHandler和生成验证码的Handler

 //将图片显示在页面上的Handler
        class TestHandler : IHttpHandler
        {
            public void ProcessRequest(HttpContext context)
            {
                FileStream fs = new FileStream(context.Server.MapPath("worm.jpg"), FileMode.Open);
                byte[] b = new byte[fs.Length];
                fs.Read(b, 0, (int)fs.Length);
                fs.Close();
                context.Response.OutputStream.Write(b, 0, b.Length);
            }
            public bool IsReusable
            {
                get
                {
                    return true;
                }
            }
        }
        //生成验证码的Handler
        class CodeHandler:IHttpHandler
        {
            public bool IsReusable
            {
                get
                {
                    return true;
                }
            }
            public void ProcessRequest(HttpContext context)
            {
                Image b = new Bitmap(50,20);
                Graphics g = Graphics.FromImage(b);
                SolidBrush sb = new SolidBrush(Color.White);
                Font f = new Font("宋体", 12);
                string str = "";
                Random r = new Random();
                for (int i = 0; i < 4; i++)
                {
                    str += r.Next(10);
                }
                g.DrawString(str,f,sb,0,0);
                b.Save(context.Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg);
            }
        }

IHttpHandler工厂:

    class TestHandlerFactory : IHttpHandlerFactory
         {
            public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
            {
               
                string fname = url.Substring(url.IndexOf('/') + 1);
                while (fname.IndexOf('/') != -1)
                    fname = fname.Substring(fname.IndexOf('/') + 1);
                string cname = fname.Substring(0, fname.IndexOf('.'));
                string className ="";

                className = "ClassLibrary831.CodeHandler";
                object h = null;
                try
                {
                    //h = new TestHandler();
                    h = Activator.CreateInstance(Type.GetType(className));
                }
                catch (Exception e)
                {
                    throw new HttpException("工厂不能为类型" + cname + "创建实例。", e);
                }
                return (IHttpHandler)h;
            }
            public void ReleaseHandler(IHttpHandler handler)
            {
            }
         }

web.config:

<httpHandlers>
    <add verb="*" path="default21.aspx,default22.aspx" type="ClassLibrary831.TestHandlerFactory,ClassLibrary831"></add>
   </httpHandlers>

这样TestHandlerFactory就会根据请求的不同页面执行不同的HttpHandler处理程序了。

代码审计

按照我个人理解代码审计其实就是看路由,跟踪危险函数/方法,熟知漏洞不同语言特性,各方面攻击姿势,结合利用。

文件操作: Upload、File、Download、Import、 Delete、Create、Rename、Readfile、Witrefile、DelFile

命令执行:Exec、Execte

定位上传关键字,找到对应dll文件

获取ContentType进行校验,将文件写到/Graphic/Images/

同上,都是检测ContentType

2个上传点,其余都是检测后缀。

posted @ 2021-09-06 23:45  nice_0e3  阅读(3355)  评论(0编辑  收藏  举报