ClickOnce是.NET用於Windows應用程序的一種便捷部署方式。不過由於便捷,導致缺少自定義操作的空間。比如需要對通過ClickOnce部署的應用程序的主程序(exe文件)進行數字簽名就比較麻煩。下面簡單分享下,在既能獲得ClickOnce的便捷功能(包括VS自動生成ClickOnce部署包)的同時,又能方便的對應用程序進行簽名。
1,為什么要進行數字簽名
為了保證系統的安全,現在Windows(比如Windows 8)對於通過網絡上下載的應用程序的執行文件都會首先阻止,並提示用戶是否要運行。這個時候,同時會提示這個應用程序的發行者。如果一個沒有進行數字簽名的應用程序,這個時候發行者就為“未知”,簽名后,就可以告知用戶這個應用程序是由你提供的。在這里,數字簽名就是保證這個應用程序是由你發行,並未被第三方更改的。
上面這種情況還好,很多時候,如果你安裝了360之類的軟件,對於未簽名的應用程序,大部分情況是阻止其運行的。如果沒有進行數字簽名,那么對用戶會造成極大困擾。
對執行文件進行數字簽名還有諸多好處,我就不一一例舉。現在購買一個代碼簽名的證書也不算貴,對於類似我們這種發行客戶端應用程序的廠商而言,是很有必要購買一個證書的。
2,幾個誤解:程序集強簽名、ClickOnce清單簽名、安裝程序簽名
程序集強簽名
.NET里面有個概念——程序集強簽名。這個只是.NET可以使用這個強簽名文件(snk)來對程序集進行簽名,保證程序集本身不被篡改。以便保證其他人引用的這個程序集是你開發的。MSDN這樣描述:
程序集簽名(也稱為強名稱簽名)賦予應用程序或組件一個唯一標識,其他軟件可用該標識來顯式標識和引用該應用程序或組件。強名稱由程序集的簡單文本名、版本號、區域性信息(如果提供)以及公鑰/私鑰對組成。
例如,強命名使應用程序作者和管理員可以指定用於共享組件將使用的一種准確的服務的版本。這使不同的應用程序指定不同的版本,而不會影響其他應用程序。 此外,還可以使用組件的強名稱作為安全證據生成兩個組件之間的信任關系。
要對程序集進行強簽名,無需使用購買的代碼簽名數字證書,用.NET提供的sn工具就可以生成snk文件,你只要保存好這個文件,就可以保證你的程序集的簽名。
但是,程序集強簽名並不等於執行文件的數字簽名(就算這個程序集是一個exe文件)。並且MSDN中明確說不應該對exe文件進行強簽名(雖然我是這樣做的)。文件的數字簽名實際上是在文件系統級別對任何文件附加一個簽名,告知操作系統此文件的發行者是誰。即可以在文件的屬性對話框中,看到“數字簽名”這項選項卡。
ClickOnce清單簽名
另外,對於ClickOnce的應用程序清單(即app.exe.manifest文件)和部署清單(即app.application文件)進行簽名。這樣的簽名實際上保證客戶端正確識別ClickOnce部署包的發行者以及完整性,保證不被第三方篡改。如果不對ClickOnce清單進行簽名的話,那么在安裝(即運行app.application文件)的時候,安裝程序就無法顯示發行者,在某些企業環境下或某些安全軟件下,就可能阻止application文件的運行(尤其你的應用程序需要獲取Full Trust權限的時候更是如此)。但是,對於ClickOnce清單進行簽名並不會對程序的執行文件進行簽名(雖然同樣需要代碼簽名數字證書)。
安裝程序簽名
使用過ClickOnce部署的同學,應該知道VS在生成ClickOnce部署包的時候,會同時生成一個setup.exe文件。同樣,ClickOnce不會自動對這個按照執行文件進行簽名。為了保證這個setup.exe能順利的在客戶端機器上運行,最好還是對其進行數字簽名。MSDN文檔中就有一節內容專門講述了這個問題——“How to: Sign Setup Files with SignTool.exe (ClickOnce)”。同樣,就算setup.exe被簽名了,應用程序真正的執行文件還是需要簽名的。
當然,正因為有了SignTool這個工具。
3,失敗嘗試:Post-Build Events
由於我生成ClickOnce部署包,是完全依賴於VS來自動生成的。所以為了最大限度的保證這種自動化,我首先嘗試在Post-Build Events中對編譯出來的exe程序集(bin文件夾內的)進行簽名。不過后來發現,ClickOnce是從obj文件夾里面復制文件;隨后對obj中的程序集進行簽名,結果ClickOnce包含的程序集還是未簽名的。我估計,ClickOnce在打包前會對程序集進行hash檢查,如果hash不對,就會自動全新編譯(跳過Build Events的執行)。經過幾次嘗試后,最后還采用ClickOnce打包完成后,再來簽名的方法。
4,最終做法:用CMD腳本對ClickOnce部署包進行處理
在重新復習了ClickOnce的一些重打包的命令之后,編寫了如下命令行腳本,可以對ClickOnce打包好的部署包中的exe文件進行簽名:
1: SET _dir=%CD%
2:
3: ECHO %_dir%
4:
5: rename eBalance.exe.deploy eBalance.exe
6:
7: signtool.exe sign /sha1 F0B5D453FE821F3DA370B87933BXXX /t http://timestamp.comodoca.com/authenticode eBalance.exe
8:
9: mage -update eBalance.exe.manifest
10:
11: mage -sign eBalance.exe.manifest -ch F0B5D453FE821F3DA370B87933BXXX -ti http://timestamp.comodoca.com/authenticode
12:
13: rename eBalance.exe eBalance.exe.deploy
14:
15: cd ..\..
16:
17: signtool.exe sign /sha1 F0B5D453FE821F3DA370B87933BXXX /t http://timestamp.comodoca.com/authenticode setup.exe
18:
19: mage -update eBalance.application -appm "%_dir%\eBalance.exe.manifest"
20:
21: mage -sign eBalance.application -ch F0B5D453FE821F3DA370B87933BXXX -ti http://timestamp.comodoca.com/authenticode
22:
23: xcopy eBalance.application "%_dir%\eBalance.application"
對上面的腳本簡單解釋一下:
5行,由於我打包部署的時候,包含了deploy后綴,所以先進行了一個重命名操作
7行,對exe執行文件進行簽名,使用的是我安裝在本機中的簽名證書
9行,更新應用程序清單(即這個應用程序會包含哪些程序集、資源和其他文件)
11行,對應用程序清單重新簽名
13行,把exe文件改回deploy后綴,以便接下來更新部署清單的時候能正常執行
17行,對setup.exe進行簽名(可選)
19行,更新部署清單,且指明對應的應用程序清單是那個
21行,對部署清單重新簽名
23行,用更新且重新簽名的部署清單覆蓋具體版本目錄里面的部署清單
這段腳本需要進入到具體的部署版本目錄里(比如:publish\Application Files\eBalance_4_1_13054_7),才能執行。
5,可選做法:手動生成ClickOnce部署包
當然,通過利用signtool、mage工具,你可以編寫一段更加復雜的腳本(甚至使用PowerShell),來完全用腳本執行簽名、生成相關清單,打包的工作。具體可以參考MSDN文檔:http://msdn.microsoft.com/zh-cn/library/xc3tc5xx.aspx
