“代码访问安全性”是 .NET Framework 的一部分,它通过控制代码的执行情况来控制对资源的访问。这种安全性功能与操作系统提供的安全性不同,是附加的安全性。
工作机制
当用户运行应用程序时,.NET Framework 公共语言运行时会将其分配到某一区域。五个可能的区域为:
区域 |
说明 |
---|---|
我的电脑 |
应用程序代码驻留在用户的计算机上。 |
本地 Intranet |
从用户 Intranet 上的文件共享中运行应用程序代码。 |
Internet |
从 Internet 上运行应用程序代码。 |
受信任站点 |
这些应用程序来自 Internet Explorer 中定义的“受信任”站点。 |
不可信站点 |
这些应用程序来自 Internet Explorer 中定义的“受限制”站点。 |
前三个区域,即**“我的电脑”、“本地 Intranet”和“Internet”**,是根据代码所在的位置进行分配的。在 Internet Explorer 中,通过将特定站点分配给“受信任站点”组或“不可信站点”组,可以重写分配内容。
系统管理员为每个区域均设置了特定的访问权限集。区域的安全级别可以设置为完全信任、中等信任、低信任或不信任。这些信任级别定义了应用程序可以访问的资源。在运行时,区域与其他安全证据(例如发行者、强名称、网站以及代码的 URL)共同确定授予代码的权限。有关安全证据的更多信息,请参见 证据。您无法控制用户计算机上的安全设置,而应用程序也必须在它运行时所遇到的安全设置中工作。这可能意味着,某些特定资源将拒绝应用程序的访问。例如,应用程序可能需要向文件写入数据,但用户系统却在运行时引发异常,拒绝该应用程序进行写访问。
您的工作就是开发应用程序,以处理这种情况。但这并不一定意味着应用程序需通过其他途径写入数据,而是需要预见可能无法写入数据的情况,并对这种可能性加以响应。可能需要使用更多异常处理,或使用 System.Security.Permissions 命名空间中的某些对象,使代码更加可靠。有关这些方法的简要说明,请参见本文稍后的一节“在部分信任的环境中进行开发”。
使用安装 .NET Framework 时安装的管理工具,可以设置区域的安全级别。若要了解有关在计算机上设置区域的安全级别的更多信息,请参见 管理工具。
完全信任
开发人员通常会在完全信任的环境中进行工作。他们将源代码保存在硬盘中,并在自己的开发计算机上测试应用程序。在此完全信任的环境中,开发人员编译的任何代码均可以在本地计算机上运行。由于本地计算机在默认情况下被定义为完全信任环境,因此不会出现安全性异常。
部分信任
部分信任用于描述所有非完全信任的区域。部署应用程序时,它可能会移动到一个新区域中,而该区域可能未授予应用程序完全信任级别。在部分信任区域运行代码的两种最常见的情况为:
运行从 Internet 下载的代码。
运行驻留在网络共享 (Intranet) 中的代码。
在部分信任区域中,可能拒绝访问的一些资源示例包括:
文件 I/O 操作,包括读取、写入、创建、删除或打印文件。
系统组件,例如注册表值和环境变量。
服务器组件,包括目录服务、注册表、事件日志、性能计数器和消息队列。
在部分信任区域中,哪些内容是不允许访问的?这很难判断。在 .NET Framework 中,每个类及其每种方法都有其各自的安全特性,其中定义了运行该方法所需的信任级别,也正是因为这些安全功能,在运行时可能无法访问安全特性。区域级别并不是简单地将信任级别映射到特性,而是授予特定类和方法的特定权限的集合。应用程序无法只查询信任级别即可预测哪些资源不可用。您可以确定应用程序是否运行在完全信任的环境中。在下一节“在部分信任的环境中进行开发”中,将介绍一种方法来实现此目的。
在部分信任的环境中进行开发
本节将使您大致了解安全性问题如何影响您编写的代码。在部分受信任环境中进行开发时,没有一种单一的解决方案。解决方案将依赖于所编写的应用程序。此外,在应用程序的执行过程中,由于信任级别可能发生更改,因此不能简单地测试现有的信任级别就继续下面的操作。
安全性异常代码
若要在部分信任的区域中进行开发,第一步便是编写可识别出现的安全性异常的代码。考虑下列代码:
Public Sub MakeABitmap()
Dim b As New System.Drawing.Bitmap(100, 100)
' Some code here to draw a nice picture in the bitmap
b.Save("c:\PrettyPicture.bmp")
End Sub
public void MakeABitmap()
{
System.Drawing.Bitmap b =
new System.Drawing.Bitmap(100, 100);
// Some code here to draw a nice picture in the bitmap
b.Save("c:\\PrettyPicture.bmp");
}
如果项目和项目程序集存储在计算机的硬盘上,且您是本地计算机上“管理员”组的成员,则运行此方法不会引发异常。如果将此应用程序部署到 Intranet 上,则当应用程序尝试保存位图对象时,可能会引发 SecurityException。如果此代码周围无 Try...Catch...Finally 语句 (Visual Basic) 或 try-catch-finally (C# Reference) 块,则应用程序将因异常而终止。这样的用户体验可能不会令人满意。如果您添加了异常处理代码,应用程序就可以:
警告用户应用程序无法完成它需要完成的所有任务。
清理现有的所有对象,以便在 catch 块后运行的代码不会失败。
您可以修改用于保存位图的代码,如下所示。所添加的代码可警告用户,由于安全性拒绝,文件未被保存;该代码还会将安全性失败与其他文件 I/O 失败(例如文件名错误)相区别。此方法不会产生任何安全漏洞。用户可以选择修改安全性以信任应用程序,或选择不运行应用程序。
Public Sub MakeABitmap()
Dim b As System.Drawing.Bitmap = Nothing
Try
b = New System.Drawing.Bitmap(100, 100)
b.Save("c:\PrettyPicture.bmp")
Catch ex As System.Security.SecurityException
' Let the user know the save won't work.
MessageBox.Show("Permission to save the file was denied, " &
"and the bitmap was not saved.")
Catch ex As System.Exception
' React to other exceptions here.
MessageBox.Show("Unable to create and save the bitmap.")
End Try
End Sub
public void MakeABitmap()
{
System.Drawing.Bitmap b = null;
try
{
b = new System.Drawing.Bitmap(100, 100);
b.Save("c:\\PrettyPicture.bmp");
}
catch (System.Security.SecurityException ex)
{
// Let the user know the save won't work.
MessageBox.Show("Permission to save the file was denied, " +
"and the bitmap was not saved.");
}
catch (System.Exception ex)
{
// React to other exceptions here.
MessageBox.Show("Unable to create and save the bitmap.");
}
}
System.Security.Permissions 命名空间中的类、特性和枚举支持对应用程序中的安全任务提供更大的控制权。如果您要编写的库可以从其他应用程序调用,您将希望该库验证调用方代码是否具有相应的权限。例如,您可以在代码文件的顶部、AssemblyInfo.vb 文件或 AssemblyInfo.cs 文件中添加以下程序集级别的特性。有关更多信息,请参见 设置程序集特性。
<Assembly: System.Security.Permissions.FileIOPermissionAttribute(
System.Security.Permissions.SecurityAction.RequestMinimum,
Write:="c:\PrettyPicture.bmp")>
[assembly: System.Security.Permissions.FileIOPermissionAttribute(
System.Security.Permissions.SecurityAction.RequestMinimum,
Write = "c:\\PrettyPicture.bmp")]
加载程序集时,运行时会验证权限。如果运行时拒绝所请求的权限,将无法加载程序集,并引发安全性异常。如果将此特性添加至独立的应用程序中,该应用程序可能无法运行。如果类库中出现该特性,在运行时该库可能无法加载。需要在调用类库的代码中添加一个 try/catch 块。
还可以使用 Demand 方法专门用于从运行时请求权限,如下所示。随后运行时可能授予或拒绝该请求。如果拒绝该请求,将引发安全性异常。可以按照如下所示重写代码,以显式请求写入位图文件的权限:
Public Sub MakeABitmap()
Dim b As System.Drawing.Bitmap = Nothing
Dim filename = "c:\PrettyPicture.bmp"
Dim permission As New System.Security.Permissions.FileIOPermission(
System.Security.Permissions.FileIOPermissionAccess.Write,
filename)
Try
permission.Demand()
Try
b = New System.Drawing.Bitmap(100, 100)
b.Save(filename)
Catch ex As System.Exception
MessageBox.Show("Unable to create and save the bitmap.")
End Try
Catch ex As System.Security.SecurityException
' Let the user know the save won't work.
MessageBox.Show("Permission to save the file was denied, " &
"and the bitmap was not saved.")
Catch ex As System.Exception
' React to other exceptions here.
MessageBox.Show("Other error.")
End Try
End Sub
public void MakeABitmap()
{
System.Drawing.Bitmap b = null;
string filename = "c:\\PrettyPicture.bmp";
System.Security.Permissions.FileIOPermission permission;
permission = new System.Security.Permissions.FileIOPermission(
System.Security.Permissions.FileIOPermissionAccess.Write, filename);
try
{
permission.Demand();
try
{
b = new System.Drawing.Bitmap(100, 100);
b.Save(filename);
}
catch (System.Exception ex)
{
MessageBox.Show("Unable to create and save the bitmap.");
}
}
catch (System.Security.SecurityException ex)
{
// Let the user know the save won't work.
MessageBox.Show("Permission to save the file was denied, " +
"and the bitmap was not saved.");
}
catch (System.Exception ex)
{
// React to other exceptions here.
MessageBox.Show("Other error.");
}
}
测试
在部分信任的区域中进行开发的第二步是在多个环境中进行测试,特别是在 Intranet 和 Internet 环境中。这样将强制引发安全性异常。一项重要的测试就是在本地计算机上创建不具备“管理员”权限的用户帐户,并尝试使用该帐户运行应用程序。
请参见
任务
如何:通过使用 RequestMinimum 标志请求最小权限