代码改变世界

3.5 强命名程序集能防范篡改

2011-12-05 15:02  iRead  阅读(348)  评论(0编辑  收藏  举报

  用一个私钥对程序集进行签名,可保证程序集是由对应公钥的持有者生成的。程序集安装到GAC时,系统对包含清单的那个文件的内容进行哈希处理,并将哈希值与PE文件中嵌入的RSA数字签名进行比较(在用公钥解除了对它的签名之后)。如果两个值完全一致,表明文件的内容未被篡改,可保证你拿到的公钥与发布者的私钥是对应的。除此之外,系统还会对程序集的其他文件的内容进行哈希处理,并将哈希值与清单文件的FileDef表中存储的哈希值进行比较。任何一个哈希值不匹配,表明程序集至少有一个文件被篡改,程序集将无法安装到GAC。

重要提示:这个机制只能保证一个文件的内容没有被篡改,但无法告诉你发布者是谁,除非你对生成公钥的发布者有绝对的信心,并确定发布者的私钥没有被“破解”。如果发布者使用Microsoft的Authenticode技术将它的身份与程序集关联,就可以知道发布者是谁了。

  应用程序需要绑定到一个程序集时,CLR根据所引用程序集的属性(名称、版本、语言文化和公钥)在GAC中定位程序集。如果能找到引用的程序集,就返回包含它的那个子目录,并加载容纳这清单的文件。以这种方式查找程序集,可以保证运行时加载的程序集和最初编译时所生成的程序集来自同一个发布者。之所以能做出这样的保证,是因为进行引用的程序集的AssemblyRef表中的公钥标记与被引用的程序集的AssemblyRef表中的公钥是匹配的。如果被引用的程序集不在GAC中,CLR会查找应用程序的基目录,然后查找应用程序配置文件中标注的任何私有路径。然后,如果应用程序是用MSI安装的,CLR会要求MSI定位程序集。如果在任何位置都找不到程序集,绑定操作会失败,并抛出一个System.IO.FileNotFoundException异常。

  如果强命名程序集的文件是从GAC之外的一个位置加载的(通过应用程序集的基目录,或者通过配置文件中的一个codeBase元素),CLR会在程序集加载时比较哈希值。换言之,应用程序每次执行并加载程序集时,都会对文件执行一次哈希处理,以牺牲一定性能为代价,保证程序集文件的内容没有被篡改。CLR在运行时检测到不匹配的哈希值,会抛出一个System.IO.FileLoadException异常。

注意:将一个强命名的程序集安装到GAC时,系统会执行一次检查,核实含有清单的那个文件没有被篡改。这个检查只在安装时执行一次。除此之外,为了增强性能,如果程序集被完全信任,并加载到一个完全信任的AppDomain,CLR不检查强命名的程序集是否被篡改。相反,从非GAC的一个目录加载强命名程序集时,CLR会校验程序集的清单文件,核实文件的内容为被篡改,造成该文件每次加载都会带来额外的性能开销。