如何:使用代码访问安全策略约束程序集
更新日期: 2004年04月12日
本页内容
目标
使用本模块可以实现:
• 配置 .NET 程序集的代码访问安全策略。
• 使用代码访问安全限制程序集的 I/O 能力。
适用范围
本模块适用于下列产品和技术:
• Microsoft® Windows® 2000 Server、Windows 2000 Professional、Windows Server™ 2003、Windows XP Professional 操作系统
• Microsoft .NET Framework 版本 1.1
如何使用本模块
为了充分理解本模块内容,请:
• 具备 Visual C# .NET 和 Visual Studio .NET 的编程经验。
摘要
管理员可以配置代码访问安全策略来限制 .NET Framework 代码(程序集)的操作。本模块描述了如何配置代码访问安全策略,从而约束程序集执行文件 I/O 的能力并限制特定目录的文件 I/O 能力。
必须了解的内容
使用 .NET Framework 1.1 配置工具创建新的权限集和新代码组。权限集定义了代码能做和不能做的事情,代码组则将权限集与具体代码关联起来,例如特定的程序集和程序集组。
除了约束文件 I/O 外,还可使用代码访问安全策略施加其他代码约束。例如,可限制代码访问那些受代码访问安全保护的其他资源类型,包括数据库、目录服务、事件日志、注册表、域名系统 (DNS) 服务器、非托管代码和环境变量。
注意: 下面的列表并未穷尽所有的资源类型,但它介绍了很多 Web 应用程序访问的常见资源类型。
在使用代码访问安全策略约束程序集前,请注意下列内容:
• 约束 Web 应用程序,使其只能访问自己虚拟目录层中的文件。可在 Web.config 中放置如下语句来使应用程序按中级信任级别运行:
<system.web>
<trust level="Medium" />
</system.web>
上面的语句使用 ASP.NET 代码访问安全策略来约束 Web 应用程序执行文件 I/O 的能力,它同时也施加了其他约束。例如,中级信任应用程序不能直接访问事件日志、注册表或 OLE DB 数据源。
• ASP.NET 代码访问安全策略的配置操作独立于企业级、计算机级和用户级的代码访问安全策略。.NET Framework 版本 1.1 配置工具仅支持企业级、计算机级和用户级策略。
必须使用文本或 XML 编辑器来维护 ASP.NET 策略。有关按中级信任运行 Web 应用程序的详细信息,请参阅模块 9 ASP.NET 代码访问安全性。
• 在构建程序集时,可使用代码访问安全通过编程施加约束。有关实现该功能的详细信息,请参阅模块 8 代码访问安全的实践。
• 通常,由于规范化问题所带来的安全风险,您应避免构建那些要从用户处接受文件名和路径的 Web 应用程序。但有时,可能需要接受输入的文件名。本“如何”部分说明了约束程序集的方法,从而确保程序集无法访问文件系统的任意内容。有关执行文件 I/O 的详细信息,请参阅模块 7 构建安全的程序集的“文件 I/O”部分和模块 8 代码访问安全的实践的“增强 Web 应用程序的安全”部分。
• 有关代码访问安全基础的详细信息,请参阅模块 8 代码访问安全的实践的“增强 Web 应用程序的安全”部分。
创建执行文件 I/O 的程序集
本步骤使用提供的文件名来创建执行文件 I/O 的程序集。
• 创建执行文件 I/O 的新程序集
1.
创建名为“FileIO”的新 Microsoft Visual C#™ 开发工具类库项目,并将“class1.cs”重命名为“FileIO.cs”。
2.
将强名称添加给程序集。 借助于强名称,您可通过数字签名来防止程序集被篡改。强名称的公钥组件也提供了代码访问安全策略的密码型强证据。管理员可使用强名称来唯一标识程序集,从而应用这一策略。
3.
使用固定的程序集版本。打开 Assemblyinfo.cs,按如下方式设置“AssemblyVersion”属性:
[assembly:AssemblyVersion("1.0.0.1")]
4.
将下面的 using 语句添至 FileIO.cs 顶部:
using System.IO;
using System.Text;
5.
将“Class1”重命名为“FileWrapper”,然后封装类以防止继承。
public sealed class FileWrapper
6.
重命名默认的构造函数,使其与类名匹配,然后更改为“private”,防止创建“FileWrapper”类的实例。此类仅提供静态方法。
7.
添加下面的公共方法,使其读取特定的文件。
public static string ReadFile(string filename)
{
byte[] fileBytes = null;
long fileSize = -1;
Stream fileStream = null;
try
{
if(null == filename)
{
throw new ArgumentException("Missing filename");
}
// 规范并验证提供的文件名
// GetFullPath:
// - 检查无效字符(由 Path.InvalidPathChars 定义)
// - 检查 Win32 非文件类型设备名称包括
// 物理驱动器、并行和串行端口、管道、邮件插槽
// 等等
// - 规范化文件路径
filename = Path.GetFullPath(filename);
fileStream = File.OpenRead(filename);
if(!fileStream.CanRead)
{
throw new Exception("Unable to read from file.");
}
fileSize = fileStream.Length;
fileBytes = new byte[fileSize];
fileStream.Read(fileBytes, 0, Convert.ToInt32(fileSize));
return Encoding.ASCII.GetString(fileBytes);
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (null != fileStream)
fileStream.Close();
}
}
创建 Web 应用程序
本步将创建一个调用文件 I/O 程序集的 Web 应用程序程序集。
• 创建 Web 应用程序
1.
将名为“FileIOWeb”的新 C# ASP.NET Web 应用程序项目添至当前解决方案。
2.
在引用“FileIO”项目的新项目中添加项目引用。
3.
将文本框添至 WebForm1.aspx,允许用户提供路径和文件名。将“Text”属性设置为“c:/temp/somefile.txt”,将“ID”设置为“txtFileName”。
4.
向 WebForm1.aspx 添加按钮,设置“Text”属性为“Read File”,设置“ID”为“btnReadFile”。
5.
双击“Read File”按钮,将下面的代码添至事件处理程序:
string s = FileIO.FileWrapper.ReadFile( txtFileName.Text );
Response.Write(s);
6.
构建解决方案。
使用非代码访问安全约束来测试文件 I/O
在默认情况下,Web 应用程序及其调用的任意本地计算机程序集都由代码访问安全策略授予完全信任。Machine.config 中默认的 <trust> 配置向 Web 应用程序分配了完全信任级:
<trust level="Full" originUrl="" />
在具备完全信任权限的情况下,Web 应用程序不受代码访问安全策略的任何约束。资源访问的成功与否完全由操作系统安全性决定。
• 使用非代码访问安全约束来测试文件 I/O
1.
使用“记事本”创建名为 Somefile.txt 的文本文件,其中包含简单的文本字符串。然后将该文件放在 C:/temp 目录中。同样在 C:/ 根目录下放置一个副本。
2.
运行 Web 应用程序,单击“Read File”。 系统显示文本文件内容。
3.
在文本框中输入 c:/somefile.txt,然后单击“Read File”。 系统显示文本文件内容。
配置代码访问安全策略来约束文件 I/O
在本步骤中,您将为“FileIO”程序集配置代码访问安全策略,并授予受限的“FileIOPermission”,使其只能访问 C:/Temp 目录中的文件。首先,创建新的权限集,其中包括受限的“FileIOPermission”。然后,创建新的代码组,使用强名称证据将新的权限集与“FileIO”程序集关联起来。
• 创建新的权限集
1.
在“管理工具”程序文件夹中,启动 .NET Framework 1.1 版配置工具。
2.
展开“运行库安全策略”节点,显示代码访问安全策略的三个级别:企业级、计算机级和用户级。配置代码访问安全策略的第四级是应用程序域级。ASP.NET 执行应用程序域级策略,但并不使用 .NET Framework 1.1 版配置工具维护。要编辑 ASP.NET 策略,必须使用文本编辑器。
有关 ASP.NET 策略和使用方法的详细信息,请参阅模块 9 ASP.NET 代码访问安全性。
3.
展开“计算机”节点。 显示“代码组”和“权限集”文件夹。每个策略文件都包含分层的代码组集合。代码组的作用是给程序集分配权限。代码组由两个元素组成:
• 成员身份条件 — 基于证据,例如程序集的强名称。
• 权限集 — 其中的权限将授予证据符合成员身份条件的程序集。
“权限集”是一种包含不同代码访问安全权限集合的分组。不同权限代表了访问特定资源类型或执行特定特权操作类型的代码权限。
4.
右键单击“权限集”,然后单击“新建”。
5.
在“名称”字段中输入“RestictedFileIO”,然后单击“下一步”。
6.
在“可用权限”列表中选择“FileIO”,然后单击“添加”。
7.
在“文件路径”列中输入“c:/temp”,选择“读”和“路径盘”(路径发现)。 路径发现权限是“Path.GetFullPath”函数必需的,该函数由“FileIO”程序集调用来规范化并验证提供的文件名。
读权限是“File.OpenRead”方法必需的,该方法由“FileIO”程序集使用来打开文本文件。
8.
单击“确定”。
9.
在“可用权限”列表中选择“安全”,单击“添加”。 执行“FileIO”程序集除了需要“FileIOPermission”外还必须具备该权限。要执行的权限由“SecurityPermission”表示,其“Flag”属性的设置是“SecurityPermissionFlag.Execution”。
10.
单击“启动程序集执行”,然后单击“确定”。
11.
单击“完成”完成权限集的创建。 您现已创建一个名为“RestrictedFileIO”的新权限集,其中包含受限的“FileIOPermission”和“SecurityPermission”。前者允许 C:/Temp 目录的读和路径发现权限,后者允许程序集执行。
• 创建新的代码组
1.
展开“代码组”,然后展开“All_Code”。
2.
右键单击“All_Code”,然后单击“新建”。
3.
输入“FileIOAssembly”作为代码组名称,然后单击“下一步”。
4.
在“选择此代码组的条件类型”下拉列表中选择“StrongName”。 使用此代码组可将“RestrictedFileIO”权限定义的特定权限应用到“FileIO”程序集。强名称通过提供密码型强证据来唯一标识程序集。
5.
指定“FileIO”程序集的公钥(由于有强名称,故一定有公钥),单击“导入”,然后浏览包含“FileIO.dll”的项目输出文件夹,单击“打开”,从程序集中提取公钥。
6.
单击“下一步”,在“使用现有权限集”下拉列表中选择“RestrictedFileIO”。
7.
单击“下一步”,单击“完成”完成代码组的创建。 您现已创建了新的代码组,它将“RestrictedFileIO”权限集定义的权限应用到“FileIO”程序集中。
8.
在右边的窗口中,选择“FileIOAssembly”代码组,然后单击“编辑代码组属性”。
9.
选中“该策略级别将只具有与此代码组关联的权限集中的权限”和“将不计算低于该级别的策略级别”。 通过选择代码组的这些属性,确保其他任意代码组(位于当前计算机级或 ASP.NET 应用程序域级)都不会影响被授予“FileIO”程序集的权限集。这确保了仅向程序集授予由先前创建的“RestrictedFileIO”权限集所定义的权限。
注意: 如果不选择这些选项,默认的计算机级策略将授予程序集以完全信任,因为程序集安装在本地计算机,并属于“My_Computer_Zone”的设置范围。
10.
单击“确定”,关闭属性对话框。
使用代码访问安全约束来测试文件 I/O
在本过程中,您将在全局程序集缓存 (GAC) 中安装“FileIO”程序集。然后,运行 Web 应用程序,并设法访问 C:/Temp 内部和外部的文件。在前几步中配置的代码访问安全策略约束了代码,结果只能访问 C:/Temp 目录中的文件。
程序集必须安装在 GAC 中,因为 ASP.NET 与域的非特定程序集一样都加载强名称。由 ASP.NET Web 应用程序调用的所有强名称程序集都必须安装在 GAC 中。有关这一问题的详细信息,请参阅模块 7 构建安全的程序集中的“强名称”部分。
注意: 通常,默认的计算机级策略和 ASP.NET 策略将授予安装在 GAC 中的程序集以完全信任。在前几步创建的代码组中分配的“该策略级别将只具有与此代码组关联的权限集中的权限”和“将不计算低于该级别的策略级别”属性确保了程序集不被授予完全信任,而仅有先前创建的“RestrictedFileIO ”权限集所定义的权限。
• 使用代码访问安全约束来测试文件 I/O
1.
使用 Gacutil.exe 实用程序将“FileIO”程序集安装在 GAC 中。 可将调用 Gacutil.exe 作为一种构建后期步骤,以确保在 Microsoft Visual Studio® .NET 内部成功构建程序集后将其置于 GAC 中。
1.
在 Visual Studio .NET 中显示“FileIO”项目的“属性”对话框。
2.
在“通用属性”中,选择“生成事件”。
3.
在“生成后事件命令行”字段中,键入“ C:/Program Files/Microsoft Visual Studio .NET 2003/SDK/v1.1/Bin/gacutil" -i $(TargetPath)”。
4.
单击“确定”,关闭项目属性对话框。
2.
重建解决方案。
3.
在命令行中运行 Iisreset.exe,强制循环 ASP.NET 进程。 这将强制重新计算授予“FileIO”程序集的权限。如果自上次运行 Web 应用程序以来,ASP.NET 应用程序域仍是活动的,则程序集仍可由 ASP.NET 缓存。
4.
运行 Web 应用程序,单击“Read File”。 应成功显示文本文件内容。您创建的策略允许“FileIO”程序集在 C:/Temp 中和子目录中读取文件。
5.
在文本框中输入 c:/somefile.txt,然后单击“Read File”。 应生成“SecurityException”,因为您配置的代码访问安全策略不允许在 C:/Temp 目录以外执行文件 I/O。
异常细节信息表明了 FileIOPermission 请求失败,显示如下:
System.Security.SecurityException:请求权限类型
System.Security.Permissions.FileIOPermission, mscorlib, Version=1.0.5000.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089 failed.