代码之家  ›  专栏  ›  技术社区  ›  Stefan Mohr

如何验证程序集是否由我的组织签名?

  •  3
  • Stefan Mohr  · 技术社区  · 14 年前

    我已经对.NET强名称过程进行了几次审查,认为我对它感到满意,但我只剩下了我认为的安全差距:

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

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

    1. 用户实现了一个实现插件使用的接口的程序集(这是非常重要的,因为插件不是分布式的——我们在内部创建它们)。
    2. 用户为这个程序集提供了自己的强名称
    3. 用户设法将其程序集注入数据库中的相应表中
    4. Web应用程序加载此程序集并实例化恶意用户实现的接口的构造函数-它现在正在执行其代码

    据我所知,.NET框架只会检查程序集是否有强名称,以及它是否被篡改-它没有提到作者的验证。

    因此,我的最后一个难题是以某种方式验证程序集中的签名实际上是我们自己的。我是否遗漏了一些已经解决的基本部分,或者强命名不是为处理这个案例而设计的?如果是这样,有人能建议如何解决这个问题吗?

    [编辑] 谢谢哈立德!我的问题是,我的一个测试插件是使用测试密钥签名的-我已经重新生成了它(不要问),并将其应用到其他程序集,但没有找到那个。结果,我认为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 回复  |  直到 14 年前
        1
  •  3
  •   Khalid Abuhakmeh    14 年前

    在我把这句话大声念出来之前,你的攻击听起来还不错。

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

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

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

    assemblyname类应该为您提供足够的信息,以破译您的签名是否与您提供人员的密钥匹配。

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