本文概述了微软NET Framework安全结构包括基于证据的安全基于角色的安全认证和授权的概念以及隔离存储密码加密和扩展性本文还概述了NET Framework安全策略带给开发人员管理员和最终用户的主要好处本文假定读者已经基本熟悉了NET Framework通用语言运行时和管理代码的概念
引言
目前的安全问题
在今天的软件环境中应用程序的来源很多它们执行很多任务对应用程序代码的信任是一个主要需求因为我们谁也不想软件或信息遭到破坏给予许可的安全策略不会允许对敏感信息的不适当的访问或将本地机器暴露给恶意的程序或甚至是有平常错误的代码
过去安全结构提供了基于用户帐号的隔离和访问控制在这些限制内给予代码完全访问权并假定由特定用户可运行的代码具有相同的信任度不幸的是如果所有程序都代表某用户运行根据用户对代码的隔离对于保护一个程序不被其它用户使用是不够的另一种情况不能被完全信任的代码经常被转移到沙箱模型中执行在此代码运行于隔离环境而不会访问大部分的服务
对今天应用程序的成功的安全解决方案必须能强化两个安全模型间的平衡它必须提供对资源的访问以便以完成有用的工作它需要对应用程序的安全性作细致的控制以确保代码被识别检测并给予合适的安全级别NET Framework就提供了一个这样的安全模型
Microsoft NET Framework安全解决方案
NET Framework安全解决方案基于管理代码的概念以及由通用语言运行时(CLR)加强的安全规则大部分管理代码需要进行验证以确保类型安全及预先定义好的其它属性的行为的安全例如在验证的代码中声明为接收字节值的访问将拒绝提供字节参数的调用因为不是类型安全的验证过程还确保了执行流只传送到已知的位置如方法入口点这个过程去除了跳转到任意位置执行的能力
验证将阻止不是类型安全的代码执行在它们引起破坏前捕获很多常见的编程错误通常的弱点如缓存溢出对任意内存或没有初始化的内存的读取对控件的随意传送都不再可能出现这将使最终用户受益因为在他们执行代码前对其进行检查这也有益于开发人员他们会发现很多常见错误(过去一直在困绕前开发)现在可以查明并能阻止它们引起破坏
CLR也能使非管理代码运行但非管理代码不能从这些安全措施中受益特殊的许可与对非管理代码的调用能力相关一个强大的安全策略能确保这些许可被恰当地给予经过很长时间后非管理代码到管理代码的移植将减少对非管理代码的调用频率
微软NET Framework安全机制的构件
基于证据的安全
NET Framework引入了基于证据的安全的概念在本质上它是对安全策略暴露出来问题的解答:
· 组合从哪个站点获得?
组合是NET Framework应用程序的构件它们组成了部署版本控制重用激活作用域安全认证的基本单元应用程序的组合是从网站上下载到客户端的
· 组合是从哪个URL获得的?
安全策略需要明确的地址而组合是从这个地址下载的
· 组合是从哪个区获得的?
区是基于代码的位置对安全标准如 Internet intranet和本机等等的描述
· 组合的强名(strong name)是什么?
强名是由组合的创建者提供了密码强化后的标识符尽管它没有提供对创建者的任何证明但它唯一标识了组合确保了组合没有被破坏过
根据对这些问题的回答及其它证据安全策略可以对赋予组合垢合适许可进行计算从多种来源可以得到证据包括CLR浏览器微软ASPNET及外壳这依赖于代码的来源
策略驱动的信任模型使用代码证据
当组合被调入内存进CLR策略系统通过收集组合的证据并在策略环境中对证据进行计算从而决定赋予组合什么样的许可权CLR策略系统然后根据评估过的证据和组合作出的许可请求给予组合一组许可只有在组合被给予了一组最少的许可后或组合根本不需要许可权组合的创建者才能知道组合正确运行通过一个或多个对特定许可的请求这样的附加需求可以被传送室策略系统
根据许可请求的类型策略系统可以进一步限制给予组合的许可(删除不必要的许可)或甚至拒绝将组合装入内存(如果运行组合所需的最小许可没有被策略给予)在不存在任何许可请求的情况下组合永远不会被给予多于策略系统将会给予的许可权限请求只是进一步限制得到的许可
安全策略包含了许多代码组这些组包含了根据证据应给予的许可权代码组描述的许可可提供给从特定的安全区域获得的组合或提供给由特定发行商签名过的组合等等尽管随CLR发行了一组默认的代码组(及相关许可)但管理员可以对这些CLR安全的进行定置以适合他们的特殊需求记住通过定义与证据相关的代码组任何东西都可以作为证据提交只要安全策略可以使用它
创建许可的的过程涉及到对证据的评估以确定代码组适用于哪个等级:企业机器和用户策略按上面顺序对这三个等级进行评估然后创建交插了三个等级的许可设置管理员可以将任何一个策略等级标记为终结(final)这样做应付阻止在其它等级上对策略做进一步评估例如管理员可以在机器级别上对组合终止策略这样就会阻止用户级策略对该组合的应用
一旦策略完成许可的最初设置也就创建了组合通过从三个方面做出特定的请求可以优化这些许可:
· 第一方面是指定为了使组合运行它必须拥有的最小许可设置如果这些许可没有给予那么组合将不同调入到内存并抛出例外
· 第二可以指定一组可选的许可尽管组合希望存在这些许可但如果无法获得这些许可它仍可以调入到内存
· 最后行为特别好的组合实际上会拒绝它们所不需的有风险的许可这三个优化选项是调入时作为声明语句实现的
在运行时许可是根据代码的执行计算的右侧的图总结了这个过程的发生顺序组合A将它的证据和来自主机的证据提供给策略评估器策略评估器在创建许可时也要考虑从组合得到的许可请求G组合A由组合A调用而A又是由组合A调用的当组合A执行一个引发安全检查的操作时A和A获得的许可同样也要进行检查以确保它们拥有A所请求的许可权限在这个过程中此过程称为堆栈遍历(walking)堆栈中每个组合的许可权限都要进行检查以确定所给予的权限设置是否包含安全检查所需要的许可如果堆栈中的每个组合被给予了安全检查所需要的许可调用将成功如何任何组合没有给予所需要的许可堆栈遍历过程失败安全例外将被抛出
图 主机和组合为策略评估器提供证据评估器使用安全策略和许可请求确定组合的许可权限应用程序中不同运行组件的许可权限然后用于作出授权决定
代码访问安全堆栈遍历可以保护代码不受攻击在精通的攻击中恶意代码欺骗受信任代码执行它独自不能运行的操作有效地利用代码的许可权限实现恶意的目的对这类攻击开发人员很难进行防备但堆栈遍历确保了如果涉及到了低级信任等级的代码有效许可将被减少到信任等级最低的代码具有的许可
结果代码将从源处获得不同的信任等级并在适合于特定的代码执行环境的限制下运行
NET Framework调用的自由安全性
一些活动如读写文件显示对话框读写环境变量可以通过包含在框架安全构架中的NET Framework方法实现这就使NET Framework能根据安全策略允许或不允许一个操作而不需要程序员做额外的工作尽管暴露了保护资源的管理类的创建者在他们的库中做了明确的安全需求使用NET Framework类库访问受保护资源的开发人员可以自由地利用代码访问安全系统;他们不必作出明确的安全调用
管理员可以通过决定给予哪些许可来优化安全策略然后依靠NET Framework处理所有的安全操作代码访问安全能阻止大部分的恶意攻击对代码的验证减少了缓存溢出和其它会导致安全攻击的不期望的行为因此应用程序和组件生来就受到了保护它们免于大多数安全问题的沖击而这些安全问题一直困绕着本地代码的实现
基于角色的安全
有时根据已认证的身份或根据与代码执行上下文相关的角色作出认证决定是合适的例如金融和企业软件可以通过评估角色信息的企业逻辑加强策略根据作出请求的用户角色可以对金融交易的数据进行限制出纳被允许可以处理一定金额的请求而多于该金额的所有工作需要监督人的角色来处理
身份可以映射到登录系统的用户或由应用程序定义相应的原则封装了身份和其它相关的角色信息(例如但并不限于此用户的组由操作系统定义)
认证和授权
认证是一个过程它接收来自用户的证书并对证书的授权进行确认如果证书是有效的那么用户就可以说他拥有已认证的身份而授权的过程是:确定认证用户是否能够访问给定的资源认证可通过系统或企业逻辑来完成通过某个API它是或获得的认证API是完全可扩展的因此开发人员根据需要使用自己的企业逻辑开发人员可以对他们的认证需求进行编码也可以修改底层的认证方法而无需对他们的代码作太大变化除了微软Windows?操作系统身份认证外还有的认证方法包括基本HTTP摘要和 Kerberos以及微软Passport和基于窗体的认证这些认证方法已经完全集成到ASPNET中了
在ASPNET窗体认证中用户提供证书并提交窗体如果应用程序簦别请求系统发送一个cookie 该cookie以某种形式包含包含了证书或包含重新获得身份的关键字接下来发送的请求在头中包含了cookieASPNET处理程序通过应用程序所期望的任何有效方法对这些请求认证和授权如果请求没有经过认证HTTP客户端将用于把请求发送到认证窗体在那里用户可能提供信任证书窗体认证有时用于个性化为已知用户的内容进行定置在一些情况下身份是问题所在而不是认证因此用户的个性化信息可以简单地通过访问用户或获得
授权的目的是确定作出请求的身份是否被给予了对给定资源的访问权ASPNET提供了两种类型的授权服务:文件授权和URL授权文件授权根据正在作用的方法和作出请求的身份决定用户使用于哪个访问控制列表URL授权是URI名称空间和不同用户或角色间的逻辑映射
隔离存储
NET Framework提供了一个特殊的功能隔离存储用于存储数据甚至是当不允许对文件进行访问时例如当从Internet下载了一个管理控件并运行它为它提供了有限的许可权但没有权力读写文件
隔离存储是一组新的用于NET支持的用于本地存储的类型和方法在本质上每个组合可以访问磁盘上一断被隔离的存储空间它不允许访问其它数据隔离存储只对为它创建的组合有效
隔离存储也可被应用程序用于保存活动记录保存设置或者将状态数据保存到磁盘上以备将来之用因为隔离存储的位置是预先决定好的所以隔离存储为指定唯一存储空间提供了一种方便的方式而不需要决定文件路径
从本地企业局域网获得的代码具有相似的限制但更少它可以访问大限额的隔离存储最后从受限站点区域(不信任站点)来的代码没有对隔离存储的访问权
加密
NET Framework提供了一组加密对象它们支持加密算法数字签名散列生成随机数是通过众所周知的运算法则实现的如RSA DSA Rijndael/AES Triple DES DES 和 RC 以及MD SHA SHA SHA 和 SHA散列算法同时还支持在IETF和WC开发的XML数字签名规范NET Framework使用加密对象支持内部服务这些对象还作为管理代码提供给需要加密支持的开发人员
如何指定安全性?
如果要对组合运行时的行为进行修改根据程序员的需要可以作出声明式安全或强迫式安全的修改
声明式安全
声明式安全使程序员可以直接在组合代码的元数据中为组合指定安全需求许可请求和所有其它形式的声明式安全是在代码中是作为定置属性指定的类属性和方法的注释用于优化许可例如声明式安全可用于类的调用者在调用方法前检查调用者是否被已知地行商签名过或有一个特定的强名
由于声明属性是组合元数据的一部分所以组合的安全需求易于辨别可以使用工具对组合进行扫描以发现哪些方法需要某些许可哪些方法断言了某些许可
当被请求的活动和许可在编译时是知道时声明式检查可作为选择的解决方案之一例如如果方法总是检查对C:\temp的写访问许可那么许可检查就会从声明中得到好处另一方面如果被请求的具有访问权的位置发生了变化那么强迫式安全也许是一个比较好的解决方案
强迫式安全
强迫式安全直接在代码中实现程序员通过程序采取安全活动并且根据安全堆栈的状态决定是给予还是拒绝许可例如当一个方法请求访问一个特定的文件时如果调用者(或方法的任何一个调用者)没有被给予必需的许可权限那么请求失败因为强迫式安全是通过程序实现的所以满足了动态需求如果你需要对一个特定文件的访问许可但该许可还要根据其它信息发生变化那么强迫式安全就是可选的解决方案
总结
NET Framework安全迎合了这种事实:软件向多样化的移动组件发发展并根据这种事实提供保护在一个细化的可扩展的策略和许可系统下用户能够运行功能强大的代码而同时减少相关的风险在没有运行时对用户作出信任决定时管理员可以在各个级别创建强壮的安全策略策略是完全可定置的开发人员能够集中解决应用程序逻辑而不用关心核心的安全问题(它由CLR透明地处理)然而开发人员可以在任何时候扩展安全模型