如何验证组件是否由我的组织签署?

时间:2010-02-02 04:35:05

标签: .net

我已经多次回顾了.NET强名称流程并认为我对此感到满意,但我认为我认为这是一个安全漏洞:

我正在开发一个系统,我们将序列化的.NET程序集存储在MS SQL数据库中。它们由面向公众的Web应用程序读取,该应用程序反序列化并缓存它们。这样做是为了允许远程添加新插件,而无需重新部署Web应用程序。

但是,我对作者验证有些担忧。 Web应用程序和插件程序集都使用相同的公钥 - 私钥具有强名称。通过这种方式,我保证插件不会被篡改,但我看到一个恶意用户可以执行自己的代码的场景:

  1. 用户实现了一个实现我们的插件正在使用的接口的程序集(这非常重要,因为插件不是分布式的 - 我们在内部创建它们。)
  2. 用户为此程序集提供了自己的强名称
  3. 用户设法将他们的程序集注入我们数据库中的相应表格
  4. Web应用程序加载此程序集并实例化恶意用户实现的接口的构造函数 - 它现在正在执行其代码
  5. 我的理解是,.NET Framework只会检查程序集是否具有强名称并且没有被篡改 - 它没有说明作者的验证。

    因此,我的最后一个难题是以某种方式验证装配中的签名实际上是我们自己的。我是否遗漏了一些已经解决过的基本部分,或者是否有强大的命名来处理这种情况?如果是这样,有人可以建议如何解决这个问题吗?

    [编辑] 谢谢哈立德!我的问题是我的一个测试插件是使用测试密钥签名的 - 我已经重新生成它(不要问)并将其应用到其他组件但是错过了那个。结果,我认为GetPublicKey()返回的是不一致的值!

    遵循此路径的任何人的代码段:

    private bool ValidateAssembly( byte[] deserializedAssembly ){
       byte[] ourKey = Assembly.GetExecutingAssembly().GetName().GetPublicKey();
       for (int i=0; i < deserializedAssembly.Length; i++){
          if ( deserializedAssembly[i] != outKey[i] )
             return false;
        }
        return true;
    }
    

    (为清晰起见,删除了任何错误处理或非公开密钥检查)

    注意只要使用相同的密钥对执行程序集(Web应用程序)和插件进行签名,此方法就可以正常工作。这对我们内部有效,但如果您的插件API是公开的,那么您需要一种不同的方式来管理信任。

1 个答案:

答案 0 :(得分:3)

在我大声朗读这句话之前,你的攻击听起来似乎是合理的。

  

用户设法将他们的程序集注入我们数据库中的相应表

如果黑客可以访问您的数据库,我认为这比担心他将要执行的代码更重要。但无论如何,下面是一些代码来获取您可能加载的程序集的公钥。您可以根据您的密钥进行检查,并确保它不是其他签名。

AssemblyName asmName = asm.GetName();
byte[] key = asmName.GetPublicKey();
bool isSignedAsm = key.Length > 0;
Console.WriteLine( "IsSignedAssembly={0}", isSignedAsm )

AssemblyName类应该为您提供足够的信息来破译您的签名是否与您为其提供的密钥相匹配。

现在,如果黑客拥有你的密钥(公共/私人),那么他就是在内部工作,这是一个更大的问题。