簡體   English   中英

從未經授權的呼叫者處安全C#程序集

[英]Secure C# Assemblies from unauthorized Callers

有沒有辦法將您的程序集保護到類/屬性和類/方法級別,以防止從另一個未由我們公司簽名的程序集中使用/調用它們?

我想這樣做,沒有強烈命名的任何要求(如使用StrongNameIdentityPermission)並堅持如何簽署程序集。 我真的不想使用InternalsVisibleTo屬性,因為在不斷變化的軟件生態系統中無法維護。

例如:

情景一

Foo.dll由我的公司簽名,Bar.dll根本沒有簽名。

Foo的A級酒吧有B級

A類有公共方法GetSomething()B類試圖調用Foo.A.GetSomething()並被拒絕

拒絕可能是一個例外或在某些方面被忽略

情景二

Foo.dll由我公司簽名,Moo.dll也由我公司簽名。

Foo有A級Moo有C級

A類有公共方法GetSomething()C類試圖調用Foo.A.GetSomething()並且不被拒絕

如果您希望將調用者限制為僅由特定證書進行了authenticode簽名的代碼,您仍然可以使用CAS(而不是StrongNameIdentityPermission)。

使用PublisherIdentityPermission就像使用任何CAS權限一樣。 或者,如果您想以聲明方式執行此操作,請使用屬性

顯然,您必須對被調用方法中的每個調用執行檢查 - 任何試圖強制執行限制的外部系統都可以使用反射輕松繞過。

從您可以使用的方法中

new StackTrace().GetFrame(1).GetMethod().Module.Assembly

獲得調用程序集。 現在你可以使用了

callingAssembly.GetName().GetPublicKey()

獲取調用程序集的公鑰並將其與被調用程序集的公鑰進行比較。 如果它們匹配 - 假設所有程序集都使用相同的密鑰對簽名 - 則調用者被接受為合法調用者。

但是有一個循環漏洞 - 第三方程序集可以與您公司的公鑰進行延遲簽名,並從數字簽名驗證中排除。 因此,加載程序將加載具有強名稱的第三方程序集和公司公鑰,即使它尚未簽名。 要關閉此循環孔,您必須檢查簽名。 沒有托管API,您必須進行P / Invoke

Boolean StrongNameSignatureVerificationEx(
   String wszFilePath,
   Boolean fForceVerification,
   ref Boolean  pfWasVerified)

fForceVerification設置為true並檢查結果是否為true

總之,每次通話可能會產生很大的開銷。 誘惑可能是緩存結果,但假設一個具有反射權限的調用者,可能並不是很難操縱這樣的緩存。 另一方面,你永遠不會100%肯定。 誰控制系統可以自由地(幾乎)做他想要的一切 - 附加調試器,修改內存內容,操作庫或整個運行時。 最后,您還必須有效地保護您的程序集免受反編譯和修改。

我見過由公司(最着名的是Pegasus Imaging)編寫的DLL,它使用挑戰/響應系統解鎖組件。 DLL的購買者提供有“購買者名稱”的“許可證代碼”,DLL的消費者隨后使用該許可證代碼來解鎖DLL特征的特定子集。

因此,當應用程序第一次使用程序集時,將在程序集中調用Unlock()方法。 用戶名和解鎖代碼傳入並運行驗證身份的算法,可能使用某種公鑰加密算法。

解鎖代碼中有一些位用於指定功能; 然后這些位在程序集中設置一些功能標志。 所有調用函數都必須檢查這些標志以確定是否啟用了相應的功能。 Unlock()方法只調用一次,並且適用於已加載程序集的生命周期。

當然,既然你必須在程序集中提供“私鑰”,這個程序不是防黑客(什么是?),但是它相當安全,並且會保持誠實的人誠實。

首先,正如您所知,使用InternalsVisibleTo是不夠的 - 您還需要對每個程序集進行簽名和強名,以確保某人不能僅僅欺騙名稱。

現在已經開始了,你必須自己開發一個挑戰 - 響應實現 - 這不是你可以做的事情,除非你願意使用你明確描述你不想要的InternalsVisibleTo方法使用。

在CR模型中,您需要在每次方法調用時傳遞某種令牌(或者只是為了實例化一個對象)。 令牌將是一個只有你的代碼可以創建一個實例的類 - 我會使它成為你想要使用的程序集的內部類,並使用InternalsVisibleTo來訪問它 - 這樣只需要管理一個類:

// SharedAssembly.dll
// marks ConsumingAssembly.dll as having access to internals...

internal sealed class AccessToken { }

public class SecuredClass
{
   public static bool WorkMethod( AccessToken token, string otherParameter )
   {
       if( token == null )
           throw new ArgumentException(); // you may want a custom exception.

       // do your business logic...
       return true;        
   }
}



// ConsumingAssembly.dll  (has access via InternalsVisibleTo)

public class MainClass
{
  public static void Main()
  {
      var token = new AccessToken(); // can create this because of IVT access
      SecuredClass.WorkMethod( token, "" );  // tada...
  }
}

您可能希望將AccessToken類放在服務提供者和使用者都知道的第三個程序集中,這樣您就不必為不同的程序集不斷維護不同的訪問令牌類組。

為每種方法構建CR機制既繁瑣又乏味。 它也不是100%萬無一失 - 有足夠時間和耐心的人可能會找到解決方法。

最佳選擇(在您的情況下可能或可能不可能)將您的私有代碼保留在您自己的服務器上,並僅將其作為Web服務(或類似的東西)公開。 這使您可以主動管理IP的可訪問性,並允許您以集中(而非分布)的方式更新訪問者。 已存在用於使用證書,消息簽名和加密來限制對Web服務的訪問的技術。 這將是控制對您的IP訪問的最可靠(並且經過驗證)的方法。

我覺得沒什么大不了的! 如果您真的需要安全性,請將您的代碼放在服務器后面並使用客戶端 - 服務器架構。 或者是Web服務。 或者像WCF或遠程處理之類的東西。 然后使用身份驗證來驗證客戶端。

哎呀你可以將所有內容設為私有,公開API並在本地根調用。

在僅限桌面的環境中保護未經授權的呼叫者的DLL只會使事情變得更復雜,更難以使用。 更不用說它內部看起來很難看。

我看到一些公約出現了。 這可能對你有用。 但它並沒有為您提供所需的“全面安全性”。 如果您有一個應該對客戶隱藏的程序集,請不要將其放在GAC中。 使用后綴為“INTERNAL”的名稱空間。

如果您不控制運行代碼的執行環境,我認為沒有辦法實現此目的。 在用戶的計算機上以完全信任運行的代碼將能夠繞過您添加的任何限制。 例如,完全信任代碼可以使用反射API調用私有或內部方法,因此即使使用InternalsVisibleToAttribute也行不通。

如果您控制執行環境,則可以創建一個AppDomain,其中您的代碼完全受信任,第三方代碼部分受信任,除非您在程序集上放置AllowPartiallyTrustedCallersAttribute (APTCA),否則無法調用您的代碼。 您可以使用SecurityCriticalSecuritySafeCritical屬性限制可以在APTCA程序集中調用哪些方法。

如何:在沙箱中運行部分受信任的代碼

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM