強式名稱組件

強式名稱組件 (Strong-named Assembly)
要註冊到 GAC 的組件,都必須是強式名稱組件,而要將組件變成強式名稱組件,必須使用一組金鑰對該組件進行簽署的動作。首先必須使用 sn.exe 產生一對金鑰,例如:

sn.exe -k MyKey.snk產生的 MyKey.snk 會包含一組公開金鑰與私密金鑰。

接著再利用這個金鑰檔簽署組件,做法是在專案屬性的「Signing」頁籤中勾選「Sign the assembly」核取方塊,並且指定金鑰的檔案名稱。


為何需要將組件延遲簽章?
由於組件的簽章代表了唯一性,對一家專門生產 .NET 元件的公司來說,所有的組件的簽章都會使用同一組金鑰,也就是說,某家公司所建立的組件都會具有相同的簽章,而經由組件的簽章,也可以得知某個組件是否是由該公司所生產的。

然而,從建立強式名稱的過程當中我們知道,開發人員必須有金鑰檔,才能建立強式名稱組件。這樣一來,公司裡面的每一個開發人員都可以拿到代表該公司的金鑰,萬一其中有人拿金鑰暗中建立了一個含有惡意程式的組件,就會影響到該公司的信譽。換句話說,金鑰應該視為公司的機密資料,一但外洩,很可能會被冒名頂替去做一些違法的事情。

另一種情況是,當你辛苦寫了一套元件或應用程式,希望不要被別人用逆向工程的方式看到原始碼,你可能會利用 obfuscator 工具將邊編譯過的組件重新"攪亂"一番。如果你事先就加入組件簽章,那麼組件再經過 obfuscator 工具更動過後,程式就不能執行了(.NET CLR 會發現組件被"污染"過了,而拒絕執行)。

組件延遲簽章的技術就是用來解決上述問題。

組件延遲簽章的做法
組件延遲簽章的做法,是只先用公開金鑰簽署組件,等到組件開發完成,要打包、發行產品時,才使用完整金鑰對該組件進行簽署(完整金鑰的保管人通常是是高階主管)。

舉例來說,假設某家公司限定只有開發部門的主管可以拿到金鑰,那麼該主管可以使用以下命令從金鑰檔中取出公開金鑰:

sn.exe -p MyKey.snk MyPublicKey.snk然後把 MyPublicKey.snk 交給其他開發人員。這樣一來,開發人員就只有拿到公開金鑰。可是開發人員如果依照前面介紹的方式簽署組件,在建立組件時就會發生編譯錯誤:

Cryptographic failure while signing assembly 'MyAsmb.dll' --
'Key file 'MyPublicKey.snk' is missing the private key needed for signing' DelaySignedAsmb
因為在為組件加入簽章時,還必須要有私密金鑰才行。此時就必須用到延遲簽章,做法是在專案屬性的「Signing」頁籤中勾選「Delay sign only」選項。這樣就可以順利在開發時期建立延遲簽章的組件了。利用此方法所建立的組件,編譯器會在組件中加入公開金鑰,並且保留一些空間給私密金鑰,以便未來正式簽署組件時寫入這個保留的空間。

但是這樣還是有問題,當其他開發人員要使用這個組件時,可以順利加入組件參考和編譯專案,可是在執行程式時卻會出現 FileLoadException:

Could not load file or assembly 'MyAsmb, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=f0bed8b38a4d3590' or one of its dependencies.
Strong name validation failed. (Exception from HRESULT: 0x8013141A)這是因為 CLR 在載入組件時,會先驗證該組件的簽章是否正確。由於組件使用了延遲簽章,組件裡面只有公開金鑰而沒有私密金鑰,因此 CLR 在驗證組件簽章時就會失敗,因而無法載入組件。因此,開發人員還必須做一件事情,就是告訴 CLR 在載入這個組件時,不要驗證它的簽章是否有效。做法是使用 sn.exe 加上 -Vr 參數,例如:

sn.exe -Vr MyAsmb.dll這個命令並不會改變 MyAsmb.dll 的檔案內容,只是在系統中加入一項註冊資訊,告訴 CLR 在載入 MyAsmb.dll 時,不要驗證它的簽章。

註:如果要恢復驗證簽章,可以用 -Vu 參數,例如:
sn.exe -Vu MyAsmb.dll


這樣一來,所有的開發人員就可以在自己的機器上順利進行開發的工作了。等到所有的組件都開發測試完畢,要發行產品時,只要由持有完整金鑰的主管對組件重新簽署就行了,做法是使用 sn.exe 加上 -R 參數,例如;

sn.exe -R MyAsmb.dll MyKey.snk

這樣會將 MyAsmb.dll 以 MyKey.snk 重新簽署,組件的專案完全不用修改或重新編譯,只要將此重新簽署過的組件部署到用戶端就行了。

留言

熱門文章