當安裝另外的一個程序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的內容,並沒有改動加密后的值。此時非常easy被程序發現出來。由於解密后的值和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的不同版本號方面。
事實上在一般的開發中我們用到的不多。最起碼從我自己淺薄的經驗來講,接觸的不多,基本上是透明的。