对于许多ASP.NET开发人员而言,共享资源的访问是一个重大挑战,当开发Web表单和Web服务时就会遇到这样的挑战。微软公司的.NET拥有全新的用户授权和认证措施,大多数与安全相关的文章和书籍都用相当的篇幅解释表单认证,但是,与IIS、网络和操作系统安全相结合来理解ASP.NET安全架构是提供最佳解决方案的关健。
(图1)
图1描述了由IIS和ASP.NET提供的基本安全表示,它与ASP安全相比有根本不同。上面的图来自MSDN的网站。当有Web请求发生时,下面的事件会依次发生。
1、用户发出HTTP请求。
2、当Web请求发生时,它会由以SYSTEM帐户运行的IIS获得。SYSTEM帐户的功能非常强大,而且拥有所有类型的权限。IIS根据选择的认证类型进行认证,并为每名经过认证的用户创建一个访问令牌。如果选择了了匿名认证,它就会为该匿名用户创建一个访问令牌,缺省情况下是IUSR_MACHINE。另外,ISS还根据配置的授权类型进行认证。例如,IIS能够配置得只接受来自特定IP地址的请求。
3、IIS将请求和被认证用户的Windows访问令牌传递给aspnet_isepi.dll,这是一个注册为处理.aspx URL的ISAPI扩展。Aspnet_isepi.dll是一个IIS模块,是IIS和ASP.NET运行时间环境之间的一座桥。Aspnet_isapi通过命名管道向工作者进程转发该请求。
4、该工作者进程是托管着CLR的aspnet_wp.exe。缺省情况下,工作者进程以ASPNET帐户运行。当安装ASP.NET框架时,系统会创建该本地帐户。与功能强大的SYSTEM帐户不同的是,ASPNET帐户的功能十分有限。ASP.NET根据其认证配置对请求者进行认证。认证以XML格式配置在该项目的web.config文件中。如果ASP.NET被配置为Windows认证,它会接受任何来自IIS的令牌,而不会进行其它认证。另外,ASP.NET还授权对请求的资源和文件的访问。例如,FileAuthorizationModel可以用来检查用户是否具有访问请求的资源所需要的权限。对于Windows认证而言,用户的访问令牌为ACL。
5、如果整个过程发展到了这一步,应用软件就会使用特定的身份访问资源。缺省情况下,ASPNET进程帐户提供这一身份。但是,如果允许模仿,可以使用用户原来的身份或对模仿进行配置,使应用程序能够以特定的身份运行。
既然安全措施已经阐明,在假设NTFC的权限被设置为网络资源的情况下,用户就可以访问数据了。在进一步向前发展之前,有二个重要问题需要解决。一个是指定和定义访问UNC共享上文件和文件夹的任务,换句话说,也就是访问网络上共享的文件和文件夹。另一个问题是决定用来完成资源访问任务的身份。为了完成第一个任务,需要首先完成第二个任务。
有几种方法可以用来访问网络资源:
·使用ASP.NET进程身份
·使用匿名用户帐户
·使用LogonUser API
·使用服务性的组件(企业服务)
使用ASP.NET进程身份似乎有很明显的缺陷。缺省情况下,当应用程序试着访问资源时,ASP.NET进程身份提供一个身份(ASPNET)。最简单的解决方案是创建一个具有与远程计算机上相匹配的用户名和密码的本地帐户。大多数企业都会有庞大的内联网,因此这一方法是不切实际的。另外,知道是谁在访问资源也是非常重要的。尽管该方法足以访问网络资源,但效率不够高;第二个方法是使用匿名帐户,例如IUSR_MACHINE。与上面的原因相同,这种方法的效率显然也不高;第三种方法是使用LogonUser API,这种方法要求通过调用Win32 LogonUser API模仿一个特定的身份,还可以通过配置ASP.NET项目web.config文件中的<identity>元素进行模仿。据MSDN上的一篇文章称,不建议用户使用以上这些方法,应当避免在Windows 2000服务器上使用它们,因为它们要求向ASP.NET帐户进程授予“作为操作系统一部分运行”的权限,从而极大地降低了web应用程序的安全性。因此,该方法也不理想。最后,也是最可行的解决该问题的方法是使用配置为作为用于访问网络资源固定身份运行的服务性组件。这种方法听起来令人胆怯,但它是目前最好的解决方案,它的架构如下图所示:
(图2)
梅耶在http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/SecNetch08.asp上发表的一一篇有关安全的文章中表示,在企业服务服务器应用程序中使用服务性组件有以下好处:
·在使用的身份方面的灵活性,不必只依赖于ASP.NET身份。
·受信任或权限较高的代码能够与主web应用程序隔离。
·增加的进程跃距提高了攻击难度,它使得黑客更难跨越进程的边界,使用具有较高权限的进程。
·如果需要手动处理LogonUser API调用的模仿,我们可以在一个与主Web应用程序隔离的进程中完成这一工作。
开发服务性组件
从COM+中接受服务的组合体被称作服务性组件。为了开发服务性组件,开发人员必须具备丰富的COM+技术经验。COM+应用程序不是传统意义上的应用程序,它不包含用户界面。COM+应用程序实际上是构成应用程序的组件、COM和.NET的容器,它不是新版的COM,也不是COM和DCOM的组合,而是遗传自MTS(微软事务服务)的一种技术。
下面是开发服务性组件所需要的步骤:
1、创建一个新类库项目,以开发作为Web应用程序类库的中间层组件。
2、添加合适的类、方法和属性。由于需要访问文件和文件夹,我们需要引入System.IO名字空间。
(图3)
3、创建一个Web窗体应用程序。
(图4)
现在就可以对组件进行测试了。为了在企业服务应用程序中实现较高的安全性,必须使用Windows认证实现模仿,这一工作可以在Web应用程序的web.config文件中实现。它使得服务性组件能够认证调用者,并根据调用者的身份作出授权决策。在开发期间,尽管组件还不是服务性组件,它仍然能够为访问共享文件和文件夹提供足够的安全性。
<authentication mode="Window" />
<identity impersonate="true" />
要进行测试,需要首先对类进行编译,然后将对象的引用添加到Web应用程序中。对类进行如下所示的初始化:
Dim objEnterprise As New AccessingSharedResources.dal_AccessNetwork()
4、创建强命名组合体
·通过依次选择Start Menu --> Programs --> Microsoft Visual Studio .NET --> Visual Studio .NET Tools --> Visual Studio .NET Command Prompt运行Visual Studio .NET Command Prompt。
·找到项目所在的目录,并输入下面的命令:sn -k KeyPair.snk。
·上面的命令会创建一个公/私钥对,Visual Studio .NET IDE可以用它们给我们的组件一个强命名。另外需要注意的是,在项目目录中创建了一个KeyPair.snk文件。
·打开AssemblyInfo.vb文件代码窗口,并添加下面的Assembly属性:
<Assembly: AssemblyKeyFile("KeyPair.snk")>
·编译该项目。这将创建强命名的组合体。
5. Add the object to the GAC (Global Assembly Cache)
6、在GAC(全局组合体缓冲区)中添加对象
·通过点击Start Menu --> Programs --> Administrative Tools --> Microsoft .NET Framework Configuration打开.NET框架配置工具。
·点击Select Assembly Cache --> Select View List of Assemblies in the Assembly Cache浏览GAC中所有的组合体。
·右击Assembly Cache图标,从弹出菜单中选择Add。
·找到该项目的bin目录中的AccessingSharedResources.dll文件,并双击它。
注意:如果命令提示行窗口仍然在运行,输入gacutil /i AccessingSharedResources.dll,也能够将对象添加到GAC中。这是在GAC中添加对象的第二种方法。
7、添加System.EnterpiseServices.dll的引用
8、引入恰当的Enterprise Services名字空间
·Imports System.EnterpriseServices
·Imports System.Runtime.CompilerServices
·Imports System.Reflection
9、在各个类中继承ServicedComponent类
Public Class dal_AccessNetwork
Inherits ServicedComponent
10、在支持服务性组件的AssemblyInfo.vb文件中添加与服务性组件相关的组合体属性。
·引入System.EnterpriseServices名字空间
·添加下面的代码:
'COM+应用程序名字
< Assembly: ApplicationName("AccessingSharedResources")>
'COM+激活类型
<Assembly: ApplicationActivation(ActivationOption.Server)>
11、设置AssemblyVersion:
据MSDN上的文章(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/SecNetch09.asp)称,当新项目创建时由Microsoft Visual Studio(r) .NET开发系统生成的缺省AssemblyVersion属性是<Assembly: AssemblyVersion("1.0.*")>。每当项目重建时,就会产生新的组合体版本,这也会产生识别服务性组件类的新的类识别符(CLSID)。如果使用Regsvcs.exe重复向组合体注册组件服务,就会在Components文件夹中看到具有不同CLSID的复制的组件。
尽管这符合严格的COM规则,能够阻止现有的可管理和不可管理的客户破坏它,在开发过程中仍然是非常烦人的。在测试和开发过程中,考虑通过使用如下所示的组合体级AssemblyVersion属性设置一个明确的版本:
<Assembly: AssemblyVersion("1.0.0.1")>
这一设置将阻碍每次编译项目时产生新的CLSID。
12、生成新的COM+应用程序,在新的COM+应用程序中注册该组合体
·运行Visual Studio .NET Command Prompt。
·找到bin目录中dll文件的位置。
·输入regsvcs /c AccessingSharedResources.dll,并键入回车。
13、修改Web应用程序
·添加System.EnterrpiseServices.dll的引用
·在web客户端软件中添加Imports System.EnterpriseServices语句
到这一步,服务性组件就全部完成了。我们可以将该组件看作一个COM+应用软件。
·通过选择Start --> Programs --> Administrative Tools --> Component Services运行Component Services Manager。
·扩展Console Root --> Component Services --> Computers --> My Computer --> COM+ Applications --> AccessingSharedResources--> Components。
(图5)
优点和缺点
使用服务性组件的优点如下所示:
·使用身份的灵活性,我们无须只依赖ASP.NET身份。
·受信任或权限较高的代码可以与主Web应用软件隔离。
·增加的进程跃距提高了系统的安全性,使得黑客更难跨过进程边界,接近权限较高的进程。
·如果需要处理带有LogonUser API调用的模仿,我们可以在与主Web应用软件隔离的进程中完成。
缺点如下所示:
·调用服务性组件的速度不如本地.NET对象快,因此应用软件的性能会受到影响。
·要求多余的步骤和代码。
·与本地.NET对象相比更难管理。
·需要在COM+应用软件中安装DLL。
结论
尽管没有利用对象集中、事物支持、同步、事件跟踪等COM+的基本功能,我们已经完成了我们的对象。只在COM+应用程序中安装本地.NET类和添加数行特殊的COM+代码就足以完成在网络上访问共享资源的任务。