zoukankan      html  css  js  c++  java
  • 在.NET环境禁止别人调用代码

    转:

    http://network.ccidnet.com/art/1136/20030815/59697_1.html

    提纲:

    ……………………………

    一、禁止未经授权的用户

    二、强名称程序集

    三、测试

    四、安全漏洞?

    ……………………………

    内容:

    ……………………………

    现在,你应该早已试着用.NET框架编写过“Hello World”程序——也许用C#,也许用VB.NET,甚至可能用托管VC++。其实对于.NET来说,用哪一种语言并不重要,因为.NET允许用一种语言编写的.NET程序方便地调用其他语言或作者写的代码。然而,既然代码共享变得如此方便,我们怎样来保证自己的代码不被未经授权的用户使用?

    在宣传.NET框架时,微软提出的一个卖点是代码访问安全(CAS,Code Access Security)的概念。由CLR(Common Language Runtime,公共语言运行时环境)执行的每一段代码都在一个安全上下文内执行,代码的授权以各种标识信息为基础,这些标识信息也是程序集的强名称(Strong Name)的构成元素,包括:

    ▲ 文件名字:程序集的文件名称,例如MyAssembly.DLL或MyProgram.EXE等。

    ▲ 区域性:程序集的目标区域环境,如en、fr或fr-CA。

    ▲ 版本:程序集的版本号。

    ▲ 公用密钥:构造程序集时如果指定了RSA签名文件,绑定到程序集的公用密钥。

    本文讨论的主要是最后一项——公用密钥。

    一、禁止未经授权的用户

    管理员可以在上述任意标识信息的基础上,执行一个安全策略,授予或取消程序集的各种执行权限。例如,管理员可以禁止某个程序集访问Internet,或禁止程序集删除本地硬盘的文件。对于管理员来说,全面地控制代码在自己的机器上可以做什么、不可以做什么无疑是很受欢迎的。但是,当开发者和管理员的出发点不同时,问题就出现了。

    考虑一下这种情形:你开发了一个软件,它要读写一个加密的、格式私有的数据文件——这是该软件保持优势的关键所在。现在,随着.NET的流行,你把软件升级到了.NET平台并予以发布。假设你的软件有一个类专门负责私有数据文件的所有I/O操作,问题出现了:只要运用ILDASM.EXE之类的命令行工具和程序逻辑工具,其他人能够方便地分析程序集的原数据,获得所有方法及其参数的详细说明。对于一个有经验的程序员来说,也许只需数分钟时间就能够了解如何运用该I/O类来操作你私有的数据文件。显然,我们不希望出现这种情形。

    其实,这只是一个简单的例子,促使人们设法保护自己代码的原因不可胜数。但无论出于什么原因,保护代码最好的办法就是避免未经授权的用户直接调用某些API函数和类。

    二、强名称程序集

    文章开头已经提到,程序集可以通过用一个RSA签名文件签名的办法实现强名称(Strong Naming)。我们创建一个公用/私有密钥对,把它保存到文件,所有用同一签名文件构造的程序集将拥有同样的公用密钥,可以相信这些程序集来自同一开发者。任何其他人都不能构造出带有同样公用密钥的签名文件,除非别人得到了你的RSA签名文件。

    假设我们要为A公司创建RSA签名文件,先进入命令行环境(最好使用VS.NET提供的快捷方式,它会自动配置路径信息)。假设构造VS.NET项目的根是C:\test,转到C:\test目录,然后执行命令:SN -k SecureProducts.snk。不带参数执行SN命令可获得SN的使用帮助。

    在C:\test目录下生成SecureProducts.snk签名文件后,下面我们构造一个程序集,然后用SecureProducts.snk签名文件把它签名。

    启动VS.NET,创建一个C#的类库项目,将它命名为SecureAssembly。打开AssemblyInfo.cs,将版本号设置为1.0.0.0,修改AssemblyKeyFile属性,使其指向刚才创建的签名文件。这两行属性修改后应当类如:

    [assembly: AssemblyVersion("1.0.0.0")]
                [assembly: AssemblyKeyFile(@"C:\test\SecureProducts.snk")]

    接下来删除项目中默认创建的Class1.cs类,另外创建一个新类SecuredClass。为SecuredClass加入一个GetTopSecretInformation 方法,代码如下:

    public class SecuredClass {
                public SecuredClass() { }
                public string GetTopSecretInformation() {
                return "Secret Code:000111";
                } }

    为了不让GetTopSecretInformation方法提供的信息落入竞争对手的手中,我们要保证只有自己的代码(带有正确公用密钥的代码)才能够创建SecuredClass类的实例并执行GetTopSecretInformation方法。

    为此,我们要获得A公司完整的公用密钥。这要用到另一个命令行工具secutil,它能够从已经编译好的程序集获得安全信息。在命令行环境中,进入SecureAssembly\obj\debug目录,执行:Secutil -hex -strongname SecureAssembly.dll > secutiloutput.txt。命令执行的结果是创建一个文本文件secutiloutput.txt,内容类如:

    Microsoft (R) .NET Framework SecUtil 1.0.3705.0
                Copyright (C) Microsoft Corporation 1998-2001. All rights reserved.
                Public Key =
                0x0024…0AC
                Name =
                SecureAssembly
                Version =
                1.0.0.0
                Success

    选中公用密钥(前缀0x除外,共320个字母。0x表示十六进制),将它复制到剪贴板。然后将公用密钥以属性的形式放入SecuredClass类定义的最前面,例如:

    [StrongNameIdentityPermission(SecurityAction.LinkDemand,
                PublicKey="0024…0AC")]
                public class SecuredClass

    这些操作的目的是:我们告诉CLR,任何试图访问该类的程序(无论是静态访问还是通过对象实例化),都必须有指定的公用密钥(LinkDemand枚举值)。如果没有,CLR将抛出异常。注意,为了让SecuredClass顺利编译,SecuredClass.cs的开头要加上using System.Security.Permissions语句。

    如果没有保存在SecureProducts.snk文件中的对应的私有密钥,任何人无法构造出拥有该公用密钥的程序集。因此,一定要保证签名文件本身的安全。

    三、测试

    下面来测试一下这种办法是否确实有效。我们要构造一个控制台应用来引用上面的类,创建SecuredClass的实例并输出机密字符串。下面是控制台应用的主要代码:

    static void Main(string[] args)
                {
                SecureAssembly.SecuredClass secClass;
                secClass = new SecureAssembly.SecuredClass();
                Console.WriteLine("锦囊秘籍:{0}",
                secClass.GetTopSecretInformation());
                }

    在不对该程序签名的情况下运行,输出如图一所示。可以看到,CLR拒绝执行SecuredClass类的GetTopSecretInformation方法。

    图一

    现在创建另外一个控制台应用(或修改原来的应用),这一次在AssemblyInfo.cs中设定:

    [assembly: AssemblyVersion("1.0.0.0")]
                [assembly: AssemblyKeyFile(@"c:\test\SecureProducts.snk")]

    再编译、运行程序,得到图二的输出结果。

    图二

    四、安全漏洞?

    还有一个必须关注的问题是:用户可能通过其他方式获得程序代码中的字符串。例如,进入命令行环境,转到SecureAssembly\obj\debug目录,执行ILDASM SecureAssembly.dll。你可以毫不费力地找到IL(中间语言)形式的方法定义,如图三。

    图三

    这不是太简单了吗?我们花了很大力气加以保护的机密信息竟然可以通过这种方式获得!无论是公用密钥、签名文件,都挡不住一个简单的免费工具ILDASM!

    如果你确实担心有人偷看代码中的字符串,解决办法是加密字符常量,或对整个程序进行模糊处理。本文介绍的技术能够有效地防止其他人调用程序集,如果你要保护的重点是程序中的字符串而不是程序逻辑,单纯运用密钥/签名文件是不够的。

  • 相关阅读:
    java 集合Map
    java 集合Collection
    Python 列表生成式, 迭代器&生成器,Json&pickle数据序列化
    Python 函数
    Python列表,字典,元组,字符串操作,文件操作,字符编码
    python的输入输出与循环
    通过数据流发送接收图片
    php中变量的详细介绍
    php数组循环的三种方式
    php session访问限制
  • 原文地址:https://www.cnblogs.com/sainaxingxing/p/1293705.html
Copyright © 2011-2022 走看看