1. 程式人生 > >轉載:.Net 程序集 簽名工具sn.exe 密鑰對SNK文件 最基本的用法

轉載:.Net 程序集 簽名工具sn.exe 密鑰對SNK文件 最基本的用法

就是 好的 image info 內容 vcenter 項目文件 麻煩 cto

.Net 程序集 簽名工具sn.exe 密鑰對SNK文件 最基本的用法

闡述簽名工具這個概念之前,我先說說它不是什麽:

  1.它不是用於給程序集加密的工具,它與阻止Reflector或ILSpy對程序集進行反編譯一毛錢關系都沒有。

  2.它很討厭人們把它和加密聯系在一起。

我再說說它是什麽:

  1.起個大名字

    sn是strong name的縮寫,正如其名,sn.exe的目的是給程序集起一個唯一的名字(Hash+name+version+culture),即簽名,保證不會讓兩個不同的DLL重名(就跟身份證不能重一樣)

  2.讓調用者識別被調用的DLL是否被篡改

    這一點是我重點要說的,我們先假設一個場景。一個黑客正在用一個銀行客戶端程序給一個賬戶轉賬,通過反編譯發現,前端主程序Bank.exe調用Transfer.dll的TransferMoney方法來進行轉賬操作。他自然地想到,如果我修改了TransferMoney方法,將金額參數乘以10,然後重新編譯成Transfer.dll再覆蓋原來的Transfer.dll,他就能成為宇宙首富!

    由這個例子得知,我們亟待解決的安全問題是,讓Bank.exe有能力得知其調用的Transfer.dll是不是被別人篡改過的。那麽我們很自然地會想到,用信息摘要算法唄~(廢話一下,不同內容摘要出來的128位字符串是絕對不一樣的

    是的!sn起的這個大名字就是這個摘要信息,我們可以在Bank.exe的引用信息裏存好了我應該調用Transfer.dll的摘要值OriHash,這樣我們就可以在調用時先摘要一下當前的Transfer.dll得出CurHash,然後比對一下OriHash和CurHash即可!過程如下圖:

2.讓調用者識別被調用的DLL是否被篡改

    這一點是我重點要說的,我們先假設一個場景。一個黑客正在用一個銀行客戶端程序給一個賬戶轉賬,通過反編譯發現,前端主程序Bank.exe調用Transfer.dll的TransferMoney方法來進行轉賬操作。他自然地想到,如果我修改了TransferMoney方法,將金額參數乘以10,然後重新編譯成Transfer.dll再覆蓋原來的Transfer.dll,他就能成為宇宙首富!

    由這個例子得知,我們亟待解決的安全問題是,讓Bank.exe有能力得知其調用的Transfer.dll是不是被別人篡改過的。那麽我們很自然地會想到,用信息摘要算法唄~(廢話一下,不同內容摘要出來的128位字符串是絕對不一樣的

    是的!sn起的這個大名字就是這個摘要信息,我們可以在Bank.exe的引用信息裏存好了我應該調用Transfer.dll的摘要值OriHash,這樣我們就可以在調用時先摘要一下當前的Transfer.dll得出CurHash,然後比對一下OriHash和CurHash即可!過程如下圖:

技術分享圖片

這似乎就是正確答案了,可是...

    這樣做有一個問題,就是關於你預先存好的那個摘要值OriHash。有兩個方面:

      方面1.一旦我正常地更新了Transfer.dll, 那摘要也就變了,也就是說你要通知Bank.exe去更新OriHash。

      方面2.由問題1引發的安全問題。

    對於方面1,我覺得是最主要的原因,一旦Transfer.dll更新了,為了比對摘要,Bank.exe需要更新OriHash,更新100次Transfer.dll,你就要更新100次OriHash,這個做法太要命了,當然這還只是麻煩層面的問題,更嚴重的是,我們可以想象到由於頻繁更新OriHash而引發的安全問題。

    對於方面2,由於你總去更新OriHash,這個環節一旦被黑客截獲,你的OriHash就不一定保證是真的了,當然我個人認為這個懷疑有點過頭了,因為DLL引用信息一般都是工具自動添加的,除非你通過某種網絡機制傳輸這個OriHash到Bank.exe所屬的項目文件(如Bank.csPRoj),此時OriHash就有了更多的被黑風險,這是一個安全問題!

    所以基於以上兩點,.Net拿出了非對稱加密算法這把利劍!(再廢話一下,非對稱加密即生成一對兒鑰匙——私鑰和公鑰,明文被該私鑰加密只能用該公鑰解密,反之亦然,所以私鑰自己要絕對保密,公鑰可以給任何人

    將OriHash用私鑰加密為CodedHash,並存儲在Transfer.dll中。然後在Bank.exe裏一次性存入這個為了調用Transfer.dll的公鑰,但一定要意識到,Transfer.dll裏面是絕對沒有私鑰的,私鑰只包含在myPair.snk文件中,也只有你拿著,並配以荷槍實彈的保安們誓死保護不被別人拿走。

    那麽新的驗證流程如下,請結合下圖:

      a.首先Bank.exe裏含有公鑰,Transfer.dll裏含有CodedHash

      b.Bank.exe用公鑰解密CodedHash

      c1.若解密成功,就證明這個CodedHash是用和我公鑰配對的那個私鑰加密的。

        c11.對Transfer.dll進行摘要得到CurHash,將其和解密的Hash對比,如果一樣則證明Transfer.dll是安全的,並且是完整的,加載即可。如果不同,則證明這個Transfer.dll是別人篡改過的,此時拒絕加載Transfer.dll

      c2.若解密失敗,則證明這個CodedHash是用別的私鑰加密的,也就是黑客弄的,此時同樣拒絕加載Transfer.dll技術分享圖片

  這樣的流程解決了之前的兩個問題,即當Transfer.dll正常更新時,不用再把新的Hash傳給Bank.exe了,Bank.exe只需用公鑰去解密CodedHash便可知曉這東西是誰發的,並通過解密了的Hash和實時計算的Transfer.dll的Hash進行對比。這裏我們邏輯上有個假定,那就是Bank.exe裏的那個為了調用Transfer.dll的那個公鑰是真的。如果你說這個被黑了怎麽辦,那我只能說,他都能改你這個Bank.exe裏的公鑰信息了,他就想改什麽改什麽了,你就束手就縛吧。另外如果你說,我們既然之前說怕傳給Bank.exe的OriHash有假,那你為什麽不怕傳給Bank.exe的公鑰有假?我只能說,你的邏輯很清晰,的確,我們無法保證,但我要說的是畢竟公鑰只傳一次,而OriHash有可能需要多次傳輸,風險概率不一樣,如果我們假定Transfer.dll永不改變,也就是說OriHash也只用傳一次,那我可以說你用不用非對稱加密算法都是一樣的,因為保證第一次給的OriHash是真的和保證第一次給的公鑰是真的,這倆的風險系數是一樣的。不知道這麽說,大家能不能明白我的意思,我也是繞了好久才捋順的。

    我們可以再假設一遍黑客可能進行的攻擊方法:(註意前提是黑客不能動Bank.exe以及內部的PubKey1)

    攻擊1:改動並覆蓋了我的Transfer.dll,但CodedHash是一模一樣的

      這種情況下,對Transfer.dll摘要的Hash和PubKey1對CodedHash解密的結果Hash是不一樣的,成功破案!

    攻擊2:改動並覆蓋了我的Transfer.dll,黑客自己生成了公鑰私鑰對,並對Transfer.dll的Hash用私鑰加密成CodedHash.

      這種情況下,當我們用PubKey1解密CodedHash時,由於公鑰PubKey1和黑客的私鑰不成對,解密時解不開的,成功破案!

    攻擊3:改動並覆蓋了我的Transfer.dll,而Transfer.dll根本不是簽名編譯的。

      這種情況下,結果和前面兩個是一樣的,成功破案!

    攻擊4:黑客兄由於拿不著你的私鑰,表示沒有其它攻擊方案了,T_T。

    至此,原理總算是說明白了。下面我就介紹如何利用sn.exe來辦這些事兒了。

    我很討厭MS把這麽多重要的任務都包裝在了sn.exe裏,首先我們有兩個工程Bank.csproj和Transfer.csproj,我們要做的就是實現上圖的流程。

      1.用sn.exe生成公鑰私鑰對文件myPair.snk。如下圖:(你要誓死保護好myPair.snk,因為裏面有私鑰,且這也是私鑰唯一存在的地方)

      2.在Transfer工程中,將myPair.snk的路徑填到AssemblyInfo.cs文件中,如下圖:

        技術分享圖片

      3.編譯Transfer工程,生成Transfer.dll。此時,編譯器瞬間完成了對Transfer.dll的Hash,並用myPair.snk中的私鑰加密了Hash成CodedHash,並將CodedHash存入Transfer.dll中,同時公鑰信息也存入了Transfer.dll中(註意絕對沒有私鑰)。

      4.在Bank工程中,重新引用Transfer.dll文件,重新編譯Bank.exe,編譯時編譯器將提取Transfer.dll中的公鑰PubKey1,並將其寫在引用Dll的描述中。當我們用反編譯工具查看Bank.exe時,我們可以查看到如下信息:

          // Transfer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3d5e0147c186af58

       PublicKeyToken即是我們所說的公鑰PubKey1。

      5.此時大功告成,無論有人用自己的私鑰編譯篡改了的Transfer.dll或者根本就沒有用私鑰簽名編譯,運行Bank.exe時會拋出如下信息:

這便是最基本的應用了,我也是參考了不少文章,其中比較重要的是http://www.windowsdevcenter.com/pub/a/dotnet/2003/04/28/strongnaming.html,該文章還介紹了延遲簽名等機制,有興趣的朋友可以看看。

  在這裏再次說明,sn.exe並不能對程序集加密阻止反編譯,只是讓調用者知道調用對象是不是想要的,僅此而已。

  另外,HTTPS也是用的類似的方案來判斷對方是不是自己人的,只是多了一個用對稱加密算法加密數據包這一步,其它和這個都是一樣的。

  祝大家在園子裏一起進步!

轉自:http://www.knowsky.com/604600.html

轉載:.Net 程序集 簽名工具sn.exe 密鑰對SNK文件 最基本的用法