1.4.2 不安全的代码
2011-11-14 15:13 iRead 阅读(259) 评论(0) 编辑 收藏 举报MicrosoftC#编译器默认生成的是安全的(safe)代码,这种代码是否安全是可验证的。然而,Microsoft C#编译器也允许开发人员写不安全的(unsafe)代码。不安全的代码允许直接操作内存地址,并可操作这些地址处的字节。这是非常强大的一个功能,通常只有在与非托管代码进行互操作,或者在提升对效率要求极高的一个算法的性能的时候,才需要这样做。
然而,使用不安全的代码会带来一个重大风险:这种代码可能破坏数据结构,危害安全性,甚至可能造成新的安全漏洞。有鉴于此,C#编译器要求包含不安全代码的所有方法都用unsafe关键字标记。除此之外,C#编译器要求使用/unsafe编译器开关来编译源代码。
JIT编译器试图编译一个unsafe方法时,它会验证包含该方法的程序集是否被授予了System.Security.Permissions.SecurityPermission权限,而且System.Security.Permissions.SecurityPermisseionFlag的SkipVerification标志已被设置。如果该标志已被设置,JIT编译器就会编译不安全的代码,并允许它执行。CLR信任这些代码,并希望对地址及字节的直接操作不会造成任何损害。如果该标志没有设置,JIT编译器会抛出一个System.InvalidProgramException或System.Security.VerificationException异常,禁止方法执行。事实上,整个应用程序都有可能在这个时候终止,但这至少能防止造成损害。
注意:默认情况下,从本地计算机或“网络共享”加载的程序集会被授予完全信任,这意味着它们能做任何事情,包括执行不安全代码。但在默认情况下,通过Internet执行的程序集不会被授予执行不安全代码的权限。如果还有不安全的代码,就会抛出上述异常之一。管理员和最终用户可以修改这些默认设置;但在这种情况下,管理员要对代码的行为负责。
Microsoft提供了一个名为PEVerify.exe的实用程序,它检查一个程序的所有方法,并报告其中还有不安全代码的方法。可针对想要引用的程序集运行一下PEVerify.exe,看看应用程序在通过内网或Internet运行时是否会出问题。
应该注意的是,为了执行验证,需要访问任何依赖的程序集中包含的元数据。所以,使用PEVerify检验一个程序集时,它必须能够定位并加载引用的所有程序集。由于PEVerify使用CLR来定位依赖的程序集,所以会采用与平时执行程序集时一样的绑定及探测规则来定位程序集。这些绑定及探测规则将在第2章和第3章讨论。
IL和知识产权保护
有的人担心IL没有为他们的算法提供足够的知识产权保护。换言之,他们认为在生成一个托管模块之后,别人可以使用一个工具(比如IL反汇编器)来进行逆向工程,轻松还原应用程序的代码所作的事情。
我承认,IL代码确实比其他大多数汇编语言高级,而且对IL代码进行逆向工程相对而言比较简单。不过,在实现服务器端代码(比如Web服务、Web窗体或者存储过程)的时候,程序集是放在服务器上的。由于没人能从公司外部拿到那个程序集,所以也没人能从公司的外部使用任何工具来查看IL。所以,这个时候的知识产权是完全安全的。
如果担心自己分发出去的程序集,可以从第三方厂商购买一个混淆器(obfuscator)实用程序。这种实用程序能打乱程序集的元数据中的所有私有符号的名称。别人很难还原这些名称,从而很难理解每个方法的作用。但要主要,这些混淆器提供的保护是有限的,因为IL必须在某个时候提供给CLR进行JIT编译。
如果觉得混淆器不能提供自己需要的知识产权保护等级,可考虑在一些非托管模块中实现你想保密的算法。在这种模块中,将包含本地CPU指令,而不是IL和元数据。然后,可利用CLR的互操作功能(假定有足够的权限)来实现应用程序的托管和非托管部分之间的通信。当然,上述方案的前提是不担心别人对非托管代码中的本地CPU指令进行逆向工程。