強名稱是由程序集的標識加上公鑰和數(shù)字簽名組成的。其中,程序集的標識包括簡單文本名稱、版本號和區(qū)域性信息(如果提供的話)。強名稱是使用相應的 私鑰,通過程序集文件(包含程序集清單的文件,并因而也包含構成該程序集的所有文件的名稱和散列)生成的。Microsoft? Visual Studio? .NET 和在 .NET Framework SDK 中提供的其他開發(fā)工具能夠將強名稱分配給一個程序集。強名稱相同的程序集應該是相同的。
通過簽發(fā)具有強名稱的程序集,您可以確保名稱的全局唯一性。強名稱還特別滿足以下要求:
-
強名稱依賴于唯一的密鑰對來確保名稱的唯一性。任何人都不會生成與您生成的相同的程序集名稱,因為用一個私鑰生成的程序集的名稱與用其他私鑰生成的程序集的名稱不相同。
-
強名稱保護程序集的版本沿襲。強名稱可以確保沒有人能夠生成您的程序集的后續(xù)版本。用戶可以確信,他們所加載的程序集的版本出自創(chuàng)建該版本(應用程序是用該版本生成的)的同一個發(fā)行者。
-
強名稱提供可靠的完整性檢查。通過 .NET Framework 安全檢查后,即可確信程序集的內容在生成后未被更改過。但請注意,強名稱中或強名稱本身并不暗含信任級別,例如由數(shù)字簽名和支持證書提供的信任。
在引用具有強名稱的程序集時,您應該能夠從中受益,例如版本控制和命名保護。如果此具有強名稱的程序集以后引用了具有簡單名稱的程序集(后者沒有這 些好處),則您將失去使用具有強名稱的程序集所帶來的好處,并依舊會產生 DLL 沖突。因此,具有強名稱的程序集只能引用其他具有強名稱的程序集。
如果您需要在幾個應用程序間共享程序集,可將其安裝到全局程序集緩存中。安裝了公共語言運行庫的每臺計算機均具有此計算機范圍的代碼緩存。全局程序集緩存中存儲了專門指定給由計算機中若干應用程序共享的程序集。要安裝到全局程序集緩存中,程序集必須具有強名稱。
全局程序集緩存中放置的程序集必須具有相同的程序集名稱和文件名(不包括文件擴展名)。例如,程序集名稱為 myAssembly 的程序集必須具有名為 myAssembly.exe 或 myAssembly.dll 的文件。 |
應當只在必要時才將程序集安裝到全局程序集緩存中來共享程序集。一般原則是:程序集依賴項保持專用,并在應用程序目錄中定位程序集,除非明確要求共享程序集。另外,您不必為了使 COM interop 或非托管代碼可以訪問程序集而將程序集安裝到全局程序集緩存。
要將程序集安裝到全局程序集緩存中的原因有以下幾點:
-
共享位置。
可將應用程序應該使用的程序集放在全局程序集緩存中。例如,如果所有的應用程序都應使用位于全局程序集緩存中的程序集,則可將版本策略語句添加到 Machine.config 文件(此文件將引用重新定向到程序集)。
-
文件安全性。
管理員通常使用訪問控制列表 (ACL) 來保護 systemroot 目錄,以控制寫入和執(zhí)行訪問。因為全局程序集緩存安裝在 systemroot 目錄中,它繼承了該目錄的 ACL。建議只允許具有“管理員”權限的用戶從全局程序集緩存中刪除文件。
-
并行版本控制。
可在全局程序集緩存中維護程序集的多個副本(名稱相同但版本信息不同)。
-
其他搜索位置。
在探測或使用配置文件中的基本代碼信息之前,公共語言運行庫會先檢查全局程序集緩存中符合程序集請求的程序集。
請注意,在有些情況下,您肯定不需要將程序集安裝到全局程序集緩存中。如果將組成應用程序的某個程序集放在全局程序集緩存中,就無法再通過使用 XCOPY 復制應用程序目錄來復制或安裝應用程序。在這種情況下,還必須將程序集移到全局程序集緩存中。
全局程序集緩存
要使用 Visual Studio .NET 創(chuàng)建小型類庫項目、生成強名稱,以及在 GAC 中安裝項目的 .dll 文件,請按照下列步驟操作:
1. | 在 Visual Studio .NET 中,創(chuàng)建一個新 Visual C# .NET 類庫項目,并將該項目命名為 GACDemo 。 |
2. |
必須使用強名稱。要生成此加密密鑰對,請使用 SN 工具。此工具位于安裝 .NET Framework 解決方案開發(fā)人員工具包 (SDK) 的 \bin 子目錄中。SN 工具易于使用。命令行語句采用以下形式:
sn -k "[DriveLetter]:\[DirectoryToPlaceKey]\[KeyName].snk"
|
3. |
在 C:\ 中創(chuàng)建一個名為
GACKey
的目錄,以便您可以輕松地找到密鑰,并從命令提示符處訪問該密鑰。
注意 : 對于大多數(shù)用戶,.NET 工具位于 C:\Program Files\Microsoft.NET\FrameworkSDK\Bin 中。鍵入以下 SN 命令前,可能需要在您的計算機上將與該路徑類似的路徑復制到 .NET bin 目錄中。從命令提示符處鍵入 cd ,右鍵單擊以粘貼該路徑,然后按 Enter,快速轉至 SN 工具所在的目錄。 鍵入以下內容:
sn -k "C:\GACKey\GACkey.snk"
|
4. |
將生成一個密鑰,但是它與項目的程序集尚無關聯(lián)。要建立此關聯(lián),請在 Visual Studio .NET 解決方案資源管理器中雙擊 AssemblyInfo.cs 文件。此文件具有一個程序集屬性列表,默認情況下,在 Visual Studio .NET 中創(chuàng)建項目時將包括這些屬性。在代碼中修改“AssemblyKeyFile”程序集屬性,如下所示:
[
assembly:AssemblyKeyFile("C:\\GACKey\\GACKey.snk")
]
通過按 Ctrl+Shift+B 來編譯項目。您不必具有任何附加代碼即可以在 GAC 中安裝 .dll 文件。
|
5. |
您可以通過使用 Gacutil 工具或者通過將 .dll 文件拖至適當?shù)哪夸泚戆惭b .dll 文件。如果您使用 Gacutil 工具,則可以使用以下命令:
gacutil -I "[DriveLetter]:\[PathToBinDirectoryInVSProject]\gac.dll"
如果您要拖動文件,請使用 Microsoft Windows 資源管理器。打開 Windows 資源管理器的兩個實例。在一個實例中,找到控制臺項目的 .dll 文件輸出的位置。在另一實例中,找到 c:\[SystemRoot]\Assembly。
將您的 .dll 文件拖到“Assembly”文件夾中。 |
用強名稱來給程序集簽名即謂之程序集強簽名!
那什么是強名稱,簽名又有什么作用?,我們先看看強名稱的概念是什么,強名稱是由程序集的標識加上公鑰和數(shù)字簽名組成的,其中程序集的標識包括簡單文本名稱,版本號和區(qū)域性信息!
Visual Studio.NET 和 .NET Framework SDK 中有工具能夠將強名稱分配給一個程序集!強名稱相同的程序集一般也是相同的!
好了,具體我們可以通過給程序集強簽名達到什么目的呢?
通過簽發(fā)具有強簽名的程序集合,可以確保名稱的全局唯一性!因為強名稱是依賴于唯一的密鑰對來確保名稱的唯一性,其他人不會生成與你相同的程序集名稱(不同的私鑰產生的名稱不同)
強名稱保護程序集的版本沿襲,因為強名稱的唯一性能夠確保沒有其他人能夠生成你的程序集的后續(xù)版本
強名稱提供可靠的完整性檢查,通過.NET Framework安全檢查后,可以確保程序集內容在生成后未被更改過!
要注意的是,具有強名稱的程序集引用其他程序集,如果這個程序集沒有強名稱,那么具有強名稱的程序集所帶來的好處,并依舊會產生DLL沖突!因此具有強名稱的程序集只能引用其他具有強名稱的程序集。
強命名程序集(Strong Name Assembly)的概念
因為不同的公司可能會開發(fā)出有相同名字的程序集來,如果這些程序集都被復制到同一 個相同的目錄下,最后一個安裝的程序集將會代替前面的程序集。這就是著名的Windows “DLL Hell”出現(xiàn)的原因。
很明顯,簡單的用文件名來區(qū)分程序集是不夠的,CLR需要支持某種機制來唯一的標識一個程序集。這就是所謂的強命名程序集。
一個強命名程序集包含四個唯一標志程序集的特性:文件名(沒有擴展名),版本號,語言文化信息(如果有的話),公有秘鑰。
這些信息存儲在程序集的清單(manifest)中。清單包含了程序集的元數(shù)據(jù),并嵌入在程序集的某個文件中。
下面的字符串標識了四個不同的程序集文件:
“MyType, Version=1.0.1.0,
Culture=neutral, PublicKeyToken=bf5779af662fc055”
“MyType, Version=1.0.1.0,
Culture=en-us, PublicKeyToken=bf5779af662fc055”
“MyType, Version=1.0.2.0,
Culture=neturl, PublicKeyToken=bf5779af662fc055”
“MyType, Version=1.0.2.0,
Culture=neutral, PublicKeyToken=dbe4120289f9fd8a”
如果一個公司想唯一的標識它的程序集,那么它必須首先獲取一個公鑰/私鑰對,然后將共有秘鑰和程序集相關聯(lián)。不存在兩個兩個公司有同樣的公鑰/私鑰對的情況,正是這種區(qū)分使得我們可以創(chuàng)建有著相同名稱,版本和語言文化信息的程序集,而不引起任何沖突。
與強命名程序集對應的就是所謂的弱命名程序集。(其實就是普通的沒有被強命名的程序集)。兩種程序集在結構上是相同的。都使用相同的PE文件格 式,PE表頭,CLR表頭,元數(shù)據(jù),以及清單(manifest)。二者之間真正的區(qū)別在于:強命名程序集有一個發(fā)布者的公鑰/私鑰對簽名,其中的公鑰 /私鑰對唯一的標識了程序集的發(fā)布者。利用公鑰/私鑰對,我們可以對程序集進行唯一性識別、實施安全策略和版本控制策略,這種唯一標識程序集的能力使得應 用程序在試圖綁定一個強命名程序集時,CLR能夠實施某些“已確知安全”的策略(比如只信任某個公司的程序集)。
How:實現(xiàn).NET Strong Named(強簽名)防止程序被篡改 |
對.Net Assembly來說, 通過反射(Reflection)機制,得到一個Assembly里面所有的函數(shù)簽名是很簡單的.因此大家都可以制作一個和原Assembly具有完全一 樣接口的Assembly來讓系統(tǒng)或者應用程序調用,這為dll hell提供了極大的便利。顯然,.Net需要提供一種機制來防止這樣的事情,尤其當我們從網(wǎng)上更新Assembly的時候,我們如何相信當前得到 Assembly就是合法的那個呢? 一種辦法是讓Assembly的最初發(fā)布者提供簽名,程序只相信具有同樣簽名的Assembly,而且除了作者,別人不能生成這個簽名。.Net Runtime提供的就是這樣一個機制。 首先我們看一下.Net Runtime是怎么識別和導入一個DLL的。在.Net中當我們說Assembly Name的時候,不是僅僅指其文件名(比如abc.dll)。實際 上,Assembly name是由四個部分構成的:Friendly Name,Culture, Pubilc Key(Token), Version。除了Friendly Name 和 Version 是一定有的,其他兩個取決于開發(fā)者有沒有指定它們。比如像我這樣的初學者就不會去做一個有Public Key的程序,如果沒有指定的話,Culture=neutral,PublicKeyToken=null。本文忽略Culture和Version對 識別和導入一個DLL的影響,因為那是另一篇文章。我們知道,Assembly 導入有顯示導入和隱式導入兩種。顯示指的是使用Assembly.Load或者Assembly.LoadFrom來動態(tài)導入一個Assembly到內存 當中。隱式指的是CLR自動導入所要用到的Assembly(和我原先理解的不同的是,CLR并不是在在程序一開始運行就導入所有Reference的 Assembly,而是當一個數(shù)據(jù)類型被用到的時候,再去解析和導入對應的Assembly)當CLR Loader決定導入一個Assembly的時候,它一定會導入和Reference階段具有相同PublicKey或者PublicKeyToken的 Assembly。否則導入失敗。比如我們在Reference的abc Assembly的PublicKeyToken是1234123412341234,那么在運行階段,它就會去找具有 1234123412341234PublicToken的Assembly,找不到便拋出異常。當然如果Reference的Assembly不具備 Publickey,.Net Runtime 就會省略這個過程,由此,我們可以看出Pulic Key或者PublicKeyToken就是我們需要的數(shù)字簽名。我們將具有Public Key的程序稱之為強簽名程序。
那么到底什么是PublicKey和PublicKeyToken?
說了這么多理論,現(xiàn)在來看看具體怎么開發(fā)和部署具備Strong Name的Assembly吧,.Net SDK已經(jīng)為我們提供了一個非常好的工具Sn.exe. 下面就Step by Step吧,
1. 產生一個試驗性的Assembly,隨便寫點代碼,用Visual Studio Class Library模板生成一個Assembly就叫 test.dll 吧. 代碼如下:
2.寫一個Console程序,Reference test.dll,調用A(),如下,
程序輸出:This is test App;
3.現(xiàn)在因為Test.dll不是Strong name的dll,任何人都可以冒用你的名義也生成一個test.dll,并且在#2的程序路徑下替換原來那個,代碼如下:
9. 如果我是一個大項目的發(fā)布者,我不想讓團隊的所有開發(fā)者都知道privatekey file,那么應該使用 sn -p test.snk publickonly.snk, 生成一個只有Publick Key的文件,并讓團隊開發(fā)者暫時使用Publickonly.snk來給程序簽名,并把test.snk藏起來,打死也不說。
|
強名稱工具 (Sn.exe) 來創(chuàng)建密鑰對:
要使用強名稱為程序集簽名,必須具有公鑰/私鑰對。這一對加密公鑰和加密私鑰用于在編譯過程中創(chuàng)建強名稱程序集。您可以使用強名稱工具 (Sn.exe) 來創(chuàng)建密鑰對。密鑰對文件通常具有 .snk 擴展名。
創(chuàng)建密鑰對
-
在命令提示處,鍵入下列命令:
sn –k <file name>
在此命令中,“文件名”是包含密鑰對的輸出文件的名稱。
下面的示例創(chuàng)建名為
sgKey.snk
的密鑰對。
sn -k sgKey.snk |
如果您需要延遲對程序集簽名并控制整個密鑰對(密鑰對不太可能在測試方案之外),可使用以下命令生成密鑰對,然后從中將公鑰提取到一個單獨的文件中。首先,創(chuàng)建密鑰對:
sn -k keypair.snk |
-
下一步,從密鑰對中提取公鑰,并將其復制到一個單獨的文件中:
sn -p keypair.snk public.snk |
-
創(chuàng)建密鑰對之后,必須將文件放在強名稱簽名工具可以找到的位置。
當使用強名稱對程序集進行簽名時,程序集鏈接器 (Al.exe) 查找與當前目錄和輸出目錄相關的密鑰文件。當使用命令行編譯器時,只需將密鑰復制到包含代碼模塊的當前目錄即可。
如果要使用 IDE(例如 Visual Studio 2005)為程序集簽署強名稱,則必須知道 IDE 查找密鑰文件的位置。例如, C# 編譯器則在包含二進制文件的目錄下查找密鑰文件。將密鑰文件放在適當?shù)捻椖磕夸浿胁⒃O置文件屬性,如下所示:
C#
|
[assembly: AssemblyKeyFileAttribute(@"..\..\key.snk")] |
更多文章、技術交流、商務合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
