visual|安全|程序|程序员|解决|问题Visual Basic .NET 和 Visual C# .NET 程序员需要解决的安全问题
Robin Reynolds-Haertle
Visual Studio Team
Microsoft Corporation
2002 年 1 月
摘要:本文着重讨论了 Visual Basic .NET 和 Visual C# .NET 开发人员在开始使用 .NET 框架时需要解决的主要安全问题。此概述讨论了 Windows 应用程序和 Web 应用程序,以及开发过程的实现、调试和部署阶段。
本文适用于 Visual Studio .NET 和 .NET 框架的最终版本。如果您使用的是预发布版本,则其中应用程序的运行可能与本文所讨论的略有不同。
目录
- 简介
- 代码访问安全性
- 完全信任
- 部分信任
- 部分信任环境的开发
- 测试
- 其他资源
- Web 应用程序
- 动态发现
- 身份验证、模拟和委托
- ASPNET 进程标识
- 在 ASPNET 标识下运行时保护文件资源的安全
- 使用 ASPNET 标识进行调试
- Visual Studio .NET 开发环境中的安全机制
- 总结
简介
与早期版本的 Visual Studio 相比,Microsoft® Visual Studio® .NET 为应用程序的运行提供了更好的安全控制。.NET 框架提供了更多的控制,同时也要求您承担更多的编程责任。在为用户创建友好易用的应用程序时,您需要解决一些安全问题。
通常在以下三种情况下需要解决安全问题:
- 运行您的应用程序的用户可能拒绝该应用程序的权限,因为应用程序所运行的位置已被指定为拒绝该用户访问某些系统资源。例如,用户可以通过配置公共语言运行时来拒绝存储在网络驱动器上的所有应用程序的文件权限。您在编写代码时应注意此问题,并且应编写代码对这种拒绝作出恰当的回应。
- 需要防止从您的 Web 服务器访问 Web 应用程序的用户在服务器上运行恶意代码或破坏数据。
- Visual Studio 的设置方式将或多或少地使服务器面临受到恶意代码攻击的危险。
代码访问安全性
代码访问安全性是 .NET 框架的一个系统,它通过控制代码的执行来控制对资源的访问。这种安全功能独立于操作系统提供的安全性,并且是对操作系统提供的安全性的补充。当用户运行您的应用程序时,应用程序将由 .NET 公共语言运行时分配到五个区域之一。这五个区域是:
- 我的电脑 - 用户计算机上的应用程序。
- 本地 Intranet - 用户的 Intranet 上的应用程序。
- Internet - 来自 Internet 的应用程序。
- 可信站点 - 来自由 Internet Explorer 定义为“可信”站点的应用程序。
- 不可信站点 - 来自由 Internet Explorer 定义为“受限”站点的应用程序。
上述每个区域都由系统管理员设置了特定的访问权限。可以将每个区域的安全级别设置为完全信任、中级信任、低级信任或不信任。信任级别定义了应用程序可以访问的资源。区域与其他安全凭证(例如发布者、强名称、Web 站点以及代码的 URL)一起确定在运行时授予该代码的权限。您无法控制用户计算机上的安全设置,但您的应用程序在运行时仍会受到即时设置的限制。这就意味着应用程序可能会被拒绝访问某些特定资源。例如,应用程序可能需要将数据写入文件,但用户的系统将通过引发异常而拒绝在运行时进行写入访问。有关安全凭证的详细信息,请参阅 Evidence(英文)。
您的工作就是开发应用程序来处理这种情况。这并不表示让您的应用程序用另外一种方法来写入数据,而是说您的应用程序应该预计到可能无法写入数据,然后对这种可能性作出响应。您可能需要使用更多的异常处理(Visual Basic 中的 Try...Catch 或 C# 中的 try...catch)或 System.Security.Permissions 命名空间中的某些对象,以使应用程序代码更加可靠。本文后面“部分信任环境的开发”一节对这些方法进行了简要说明。
区域的安全级别可以通过随 .NET 框架一起安装的“管理工具”来进行设置。有关在计算机上设置区域安全级别的详细信息,请参阅 Administration Tools(英文)。
完全信任
开发人员通常在完全信任环境中工作。他们将源代码存放在硬盘驱动器上,并在用于开发的计算机上对其应用程序进行测试。在这种完全信任环境中,开发人员编译的任何代码都可以在本地计算机上运行。由于本地计算机被默认定义为完全信任环境,因此不会出现安全异常。
部分信任
部分信任是指完全信任区域以外的所有区域。部署应用程序时,应用程序可能会移至新的区域,而新区域可能不完全信任应用程序。在部分信任环境中运行代码的两种最常见的情况是:
- 运行从 Internet 下载的代码。
- 运行驻留在网络共享位置 (Intranet) 的代码。
在部分信任区域中可能会被拒绝访问的资源示例包括:
- 文件 I/O,包括文件的读取、写入、创建、删除或打印。
- 系统组件,如注册表值和环境变量。
- 服务器组件,包括目录服务、注册表、事件日志、性能计数器和消息队列。
在部分信任环境中哪些内容是不允许的呢?这不太容易确定。.NET 框架中的每个类以及每个类中的每种方法都有一个安全属性,用于定义运行该方法所需的信任级别,并且正是由于这些安全功能,使得在运行时可能无法访问该属性。区域级别并不只是信任级别到属性的简单映射,而是一个授予特定类和方法的特定权限的集合。您的应用程序无法只是简单地查询信任级别然后就可以预计哪些资源不可用。您可以确定应用程序是否在完全信任环境中运行。在下一节“部分信任环境的开发”中,我们将介绍一种方法。
部分信任环境的开发
本节简要介绍了安全问题可能会对编写的代码产生什么样的影响。部分信任环境的开发没有单一的解决方案。您的解决方案取决于您所编写的应用程序。此外,由于信任级别在应用程序的执行过程中可能会发生变化,因此不能仅测试现有的信任级别,然后就继续执行。
开发部分信任区域的第一步是编写能够识别即将发生安全异常的代码。请注意以下代码:
' Visual BasicPublic Sub MakeABitmap() Dim b As Bitmap = New Bitmap(100, 100) ' 此处的代码将以位图格式绘制一张漂亮的图片 b.Save("c:\PrettyPicture.bmp")End Sub// C#public void MakeABitmap(){ Bitmap b = new Bitmap(100, 100); // 此处的代码将以位图格式绘制一张漂亮的图片 b.Save("c:\\PrettyPicture.bmp");}
如果项目和项目程序集存储在您计算机的硬盘驱动器上,并且您是计算机 Administrators 组的成员,则此方法在运行时不会引发异常。如果将此应用程序部署到您的 Intranet,则当应用程序试图保存位图对象时,将引发 System.Security.SecurityException(请参阅 SecurityException Class [英文])。如果此代码周围没有 Try...Catch(在 Visual Basic 中)或 try...catch(在 C# 中)块,则应用程序将因异常而终止。这会令用户感到不满意。如果您添加异常处理代码,应用程序就能够:
- 警告用户应用程序无法完成所有需要完成的任务。
- 清除所有现有对象,以便 catch 块后面的代码能够成功运行。
您可以按如下所示修改保存位图的代码。添加的代码将警告用户该文件因安全性被拒绝而未能保存,从而将安全性失败与文件 I/O 失败(例如不正确的文件名)区分开来。这种方法不会产生任何安全漏洞。用户应修改安全设置以信任您的应用程序,否则应用程序将不会运行。
' Visual BasicPublic Sub MakeABitmap() Dim b As Bitmap Try b = New Bitmap(100, 100) b.Save("c:\PrettyPicture.bmp") Catch ex As System.Security.SecurityException ' 告知用户保存失败。 MessageBox.Show("拒绝授予保存该文件的权限," & _ "未保存此位图。") Catch ex As System.Exception ' 此处对其他异常作出反应。 MessageBox.Show(ex.Message) End TryEnd Sub// C#public void MakeABitmap(){ Bitmap b = null; try { b = new Bitmap(100, 100); b.Save("c:\\PrettyPicture.bmp"); } catch (System.Security.SecurityException ex) { // 告知用户保存失败。 MessageBox.Show("拒绝授予保存该文件的权限," + "未保存此位图。"); } catch (System.Exception ex) { // 此处对其他异常作出反应。 MessageBox.Show(ex.Message); }}
使用 System.Security.Permissions(英文)命名空间中的类、属性和枚举,可以对应用程序中安全任务进行更多的控制。如果您在编写可从其他应用程序调用的库,则可以让库验证调用代码的权限。例如,您只需在代码文件的顶部添加以下程序集级别的属性。加载该程序集时,运行时将验证权限。如果运行时拒绝所请求的权限,程序集将无法加载并且将引发一个安全异常。如果向独立的应用程序添加此属性,则应用程序可能不会运行。如果此属性出现在类库中,则可能不会在运行时加载该库。您需要在调用此类库的代码中添加 try/catch 块。
' Visual Basic<Assembly: System.Security.Permissions.FileIOPermissionAttribute( _SecurityAction.RequestMinimum, Write:="c:\PrettyPicture.bmp")> // C#[assembly: System.Security.Permissions.FileIOPermissionAttribute(SecurityAction.RequestMinimum, Write="c:\\PrettyPicture.bmp")]
您也可以专门向运行时请求权限,下面的示例中使用了 Demand 方法。运行时可能允许或拒绝该请求。拒绝请求是通过引发安全异常来实现的。您可以按如下所示重新编写代码,以明确请求写入位图文件的权限:
' Visual BasicPublic Sub MakeABitmap() Dim filename As String = "c:\PrettyPicture.bmp" Dim permission As FileIOPermission = _ New FileIOPermission(FileIOPermissionAccess.Write, _ filename) Dim b As Bitmap = Nothing Try b = New Bitmap(100, 100) permission.Demand() b.Save(filename) Catch ex As System.Security.SecurityException ' 告知用户保存失败。 MessageBox.Show("拒绝授予保存该文件的权限," & _ "未保存此位图。") Catch ex As System.Exception ' 此处对其他异常作出反应。 MessageBox.Show(ex.Message) End TryEnd Sub// C#using System.Security.Permissions;public void MakeABitmap(){ string filename = "c:\\PrettyPicture.bmp"; FileIOPermission permission = new FileIOPermission(FileIOPermissionAccess.Write, filename); Bitmap b = null; try { b = new Bitmap(100, 100); permission.Demand(); b.Save(filename); } catch (System.Security.SecurityException ex) { // 告知用户保存失败。 MessageBox.Show("拒绝授予保存该文件的权限," + "未保存此位图。"); } catch (System.Exception ex) { // 此处对其他异常作出反应。 MessageBox.Show(ex.Message); }}
测试
开发部分信任区域的第二步是在多个环境中进行测试,尤其是在您的 Intranet 和 Internet 上。这将强制引发安全异常。