.NET中的PublicKeyToken以及强命名问题

在.NET的GAC出现之前,曾经有DLL Hell的问题。这是因为当时对于共享的DLL的处理方式,是通过采用注册表的方式实现的。当我们安装一个程序A的时候,这个程序包含一个共享的DLL,那么这个DLL就会就会写入到注册表中,但是注意这里并没有写入版本信息,只是告诉你在哪个地方有一个叫做XX的DLL可以使用。当安装另外的一个程序B的时候,也包含这个共享的DLL,但是是一个更加新一些的版本,系统会发现这个DLL已经注册存在了,就会用这个DLL去覆盖原来的DLL,但是因为注册表中前后没有任何版本的标示,所以系统还是认为这就是一个DLL.
但是现在已经更新了DLL,A程序可能会出现使用这个DLL的时候不兼容的现象,但是此时如果你重装A程序,再把共享DLL换回去,那么B程序又可能出现不兼容的现象。这就是DLL HELL问题。引发这个问题的原因,还是同一个DLL不能多个版本同时存在的问题。

DLL Hell 是指当多个应用程序试图共享一个公用组件(如某个动态连接库(DLL)或某个组件对象模型(COM)类)时所引发的一系列问题。最典型的情况是,某个应用程序将要安装一个新版本的共享组件,而该组件与机器上的现有版本不向后兼容。虽然刚安装的应用程序运行正常,但原来依赖前一版本共享组件的应用程序也许已无法再工作。

然后GAC的出现,解决了这个问题。GAC中对于可以同时存在同一个DLL的多个不同的版本。如果多个程序都用到了这个DLL,那么这个程序就可以到GAC中去找相应版本的DLL.但是在GAC中,比如说同一个Data.dll,即使有多个版本的文件,但是其文件名都应该全是Data.dll,而且在不同的目录总,其version信息不是在文件名中体现出现了,而是在DLL的头信息中存储的。每个程序都会有一个程序集清单,这个清单存在和程序同名的.manifest文件中,里面列出其所需要的所有依赖,这儿所列出的依赖可不是简单地靠文件明来区分的,而是根据一种叫做“强文件名”的东西区分的。

	<?xml version=‘1.0‘ encoding=‘UTF-8‘ standalone=‘yes‘?>
	<assembly xmlns=‘urn:schemas-microsoft-com:asm.v1‘ manifestVersion=‘1.0‘>
		<dependency>
			 <dependentAssembly>
				<assemblyIdentity type=‘win32‘ name=‘Microsoft.VC80.CRT‘ version=‘8.0.50608.0‘ processorArchitecture=‘                                                                             x86‘ publicKeyToken=‘1fc8b3b9a1e18e3b‘ />
 			</dependentAssembly>
 		</dependency>
	</assembly>

我们发现原来这是一个XML格式的文件,其中<dependency>这一部分指明了其依赖于一个名字叫做Microsoft.VC80.CRT的库。但是我们发现,<assemblyIdentity>属性里面还有其它的东东,分别是  type系统类型,version版本号,processorArchitecture平台环境,publicKeyToken公匙(一般用来标示一个公司),把他们加在一起便成了“强文件名”了,有了这种“强文件名”,我们就可以根据其区分不同的版本、不同的平台,总之,有了这种强文件名,系统中可以有多个不同版本的相同的库共存而不会发生冲突。

其实PublicKeyToken就是Public Key的简单形式,我们就可以把PublicKeyToken当成PublicKey.这里说明一下PublicKeyToken的存在。PublicKeyToken的作用就是确定要加载的DLL一定要是最初的那个DLL,其实,这一方面也起到了安全方面的防范问题。比如说,有的程序,有人写了一个同名的DLL覆盖了你原来的DLL,程序如果不加分辨就使用这个DLL,可能就有安全问题了。那么PublicKeyToken是这么样来确保这个唯一性的呢?

这里涉及到了加密算法。最初DLL的开发者在开发这个DLL的时候,会加密这个DLL,使用的加密方法就是公钥私钥的方法。公钥与私钥是同时存在并且唯一对应的。对于同一段内容,用私钥加密之后,只有用公钥才能解密。如果用其他的私钥加密的东西,用这个公钥是解不开任何东西的。DLL开发者有自己的私钥,而这个私钥别人是不知道的,是保密的,在DLL开发的时候用私钥加密,并且把公钥信息写入到程序中。当这个程序开发完成后,在一台计算机上运行的时候,系统会从程序的程序清单中去找用到了哪个DLL,并且去查看这个DLL的版本,而且要用PublicKeyToken来确保这个DLL的原始性。那么是通过一个怎么样的过程来确保这个DLL的原始性呢?比如说,有一个人在你的电脑上,在你安装好这个程序后,到你程序的安装目录下,用一个同名的,具有同样的命名空间和类的DLL替换掉了你原来的DLL,系统是怎么能够发现的呢?程序在运行的时候,会从程序的程序清单中取看用到了哪个dll,这个dll的公钥是多少。(我认为这个程序清单是轻易不能被篡改的,如果这个都能篡改了,那么程序就无安全性可言了。起码我是这样认为的。)然后去GAC中或者程序的目录下寻找这个DLL。在这个DLL的头文件中有一些信息,是DLL的内容和加密后的字符串。程序会用公钥去解密这个字符串,如果解密出的内容和DLL中记录的内容一致,那么就证明这个DLL是原始的,没有被篡改过的。

下面我们考虑几种可能被篡改的情况

有人仅仅修改了DLL的内容,并没有修改加密后的值,此时很容易被程序发现出来,因为解密后的值和DLL内容不一致,程序会提示异常。

有人不仅修改了DLL的内容,还想修改加密后的值,但是要知道,此时的用户是没有原来的开发者的私钥的,如果他随便用一个私钥加密,那么在程序解密的是,用那个公钥是解密不出来任何东西的,因为公钥私钥是对应的。此时,程序会提示异常。这篇文章比较细致的解释了公钥私钥对于DLL加密的过程。

有时候会在Web.config文件中Runtime标签下看到一些<runtime>bindingRedirect的内容,这里涉及到了PublicKey。这里的作用是把不同版本的文件映射到某一个特定的版本,即程序清单中记载的某个dll是2.0的版本,可是程序在运行的时候在GAC中只找到1.0的版本,那么告诉程序此时不提示异常,只要把这个1.0版本当成2.0版本就可以了。

  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
    <dependentAssembly>
      <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35"/>
      <bindingRedirect oldVersion="1.0.0.0" newVersion="2.0.0.0"/>
    </dependentAssembly>
  </assemblyBinding>
  </runtime>

总结:PublicKeyToken或者PublicKey不仅仅是用于安全方面,也是用于区别同一个DLL的不同版本方面。其实在一般的开发中我们用到的不多,最起码从我自己浅薄的经验来讲,接触的不多,基本上是透明的。

.NET中的PublicKeyToken以及强命名问题,布布扣,bubuko.com

时间: 2024-10-15 23:31:30

.NET中的PublicKeyToken以及强命名问题的相关文章

如何创建强命名程序集, 如何查看强命名程序集的PublicKeyToken

1. 在Visual Studio中的class library工程上点右键, 选择properties. 2.  选择左边的Signing选项卡. 3. 勾选Sign the assembly复选框. 在下拉列表中选择<New...>. 4. 在弹出的对话框中给snk文件起一个名字. 按OK. 5. 程序集强命名完成. 如何查看强命名程序集的public key token ========================= 有时候你需要在web.config文件中或者其他地方引用自己写的强

DevExpress 重编译 替换强命名 修改源码

本文以DevExpress 11.1.8举例 必须满足几个条件 1. 必须有DXperience相应版本的全部源代码SourceCode.把全部源代码复制到X:\Program Files\DevExpress XXX\Components\Sources目录.目标目录的默认位置是在C:\Program Files\DevExpress 20XX\Components\Sources(其中X.X为应替换相应的版本号,以下不再重复说明). 2. 必须有一个强名称的文件.该文件可以是你自己生成的,或

强命名程序集,签名,延迟签名

强命名程序集 如果一个程序集有一个唯一的标记,那么这个程序集就可以叫做强命名程序集.在.NET框架中是通过公钥/私钥加密来产生这个唯一标记的.一个强命名程序集包含四个唯一标志程序集的特性:文件名(没有扩展名),版本号,语言文化信息(如果有的话),公有秘钥. 这些信息存储在程序集的清单(manifest)中.清单包含了程序集的元数据,并嵌入在程序集的某个文件中.下面的字符串标识了二个不同的程序集文件: “MyType, Version=1.0.1.0,Culture=neutral, Public

学习 第三章CLR共享程序集和强命名程序集

CLR 支持两种程序集:弱命名程序集(weakly named assembly)和强命名程序集(strongly named assembly) 程序集可采用两种方式部署:私有和全局 弱命名程序集只能以私有方式部署 强命名程序集部署即可私有又全局. 强命名程序集具有4个重要特性:文件名(不计扩展名),版本号,语言文化,公钥 例如:"MyTypes,Vesion=1.0.8123.0,Culture=neutral,PublicKeyToken=b77a5c561934e89" 注意:

CLR 关于强命名程序集 .

如何创建强命名程序集(Strong Name Assembly)     创建一个强命名程序集首先需要获得一个用强命名实用工具   (Strong Name Utility,即SN.exe,.NET SDK自带)产生的密钥.   下面简要介绍一下SN.exe的一些用法. 要产生一个公钥/私钥对:     a)SN –k MyCompany.Keys   该命名告诉SN.exe创建一个名为MyCompany.keys的文件.MyCompany.keys文件将包含以对以二进制格式存储的公有密钥和私有

第三章 共享程序集和强命名程序集

1. 概述 本章的重点是如何创建可由多个应用程序访问的程序集. 2. 名词解释 ① 公钥标记:从公钥派生的一个小的哈希值. 3. 主要内容 3.1 两种程序集,两种部署   CLR支持两种程序集:弱命名程序集 和 强命名程序集. 一个程序集可以采取两种方式来部署:私有 或 全局. 弱命名程序集只能私有部署,强命名程序集两种部署皆可. 3.2 为程序集分配强名称 强命名程序集具有四个重要组成部分: ① 一个文件名 ② 一个版本号 ③ 一个语言文化标识 ④ 一个公钥(一般用 公钥标记). 用SN.e

03.共享程序集和强命名程序集

进行私有部署时,程序集放在应用程序的基目录(或者它的一个子目录)中的,这个应用程序专用的.以私有方式部署程序集,可以对程序集的命名.版本和行为进行全面的控制 CLR支持两种程序集,一种是弱命名程序集,一种是强命名程序集 强命名程序集使用发布者的公钥/私钥对进行签名,它唯一性地标识了程序集的发布者 弱命名程序集只能进行私有部署,"全局部署的程序集"是部署到一些已知的位置的程序集 强命名程序集 具有4个重要的attributes,它们共同对程序集进行唯一性标识:一个文件名.一个语言文化,一

使用强命名程序集防范篡改

CLR支持两种程序集:强命名程序集.弱命名程序集,两者的区别在于,强命名程序集是被发布者使用了自己的公钥/私钥对进行了程序集的签名,能唯一性标识程序集的发布者的程序集,并且可以使用密钥对程序集进行唯一性标识.保护和版本控制,这里所提到的保护就是我们需要一起讨论的程序集防篡改. 首先我们一起来看个例子,这样能简单明了地说明使用强命名程序集的必要性. 我们建立一个WinForm程序Nick.WinFormApp,添加一个登录窗体,并且在此项目内引用名为Nick.AuthProvider的程序集,用于

.NET程序集强命名删除与再签名技术 源代码剖析

如果你想去除一个程序集的强签名(strong name),目前为止可以有两个途径 1  反编译为IL代码,删除签名部分,再编译为程序集 2  应用Re-Sign程序,直接对一个程序集再签名 生成和读取强命名 先来看,如何生成.NET的签名文件,调用命令SN传入参数. 下面的代码读取该文件, FileStream keyPairFile = File.OpenRead(“key.sn”); this.byte_2 = new StrongNameKeyPair(keyPairFile).Publi