.NET程序集插件安全性

Joh*_*zen 11 c# security reflection plugins

我在许多应用程序中使用了以下代码来加载暴露插件的.DLL程序集.

但是,我以前总是关注功能而不是安全性.

我现在计划在Web应用程序上使用此方法,该应用程序可供我以外的组使用,并且我希望确保该功能的安全性是最好的.

private void LoadPlugins(string pluginsDirectory)
{
    List<IPluginFactory> factories = new List<IPluginFactory>();

    foreach (string path in Directory.GetFiles(pluginsDirectory, "*.dll"))
    {
        Assembly assembly = Assembly.LoadFile(path);
        foreach (Type type in assembly.GetTypes())
        {
            IPluginEnumerator instance = null;
            if (type.GetInterface("IPluginEnumerator") != null)
                instance = (IPluginEnumerator)Activator.CreateInstance(type);
            if (instance != null)
            {
                factories.AddRange(instance.EnumerateFactories());
            }
        }
    }

    // Here, I would usually collate the plugins into List<ISpecificPlugin>, etc.
}
Run Code Online (Sandbox Code Playgroud)

我头几个问题:

  1. 此函数读取整个目录,并不关心它加载的程序集,而只是加载所有程序集.有没有办法在使用Assembly.LoadFile()加载程序集之前检测程序集是否是有效的功能.NET程序集?
  2. 应该在函数中添加什么样的异常处理,以防止程序集初始化停止我的代码?
  3. 如果我想否认程序集有权执行以下操作:读/写文件,读/写注册表等,我该怎么做?

我应该担心还有其他安全问题吗?

编辑:请记住,我希望任何人能够编写插件,但我仍然希望是安全的.

Blu*_*que 13

1)强有力地命名具有特定键的组件.

  • 必须把它在GAC
  • 您可以重复使用一个键来签署多个程序集
  • 当您重新使用密钥时,您会在每个已签名的程序集上获得相同的"公钥"

2)在加载时,检查组件是否已用您期望的键命名

  • 您可以将公钥存储为二进制文件,嵌入式资源,或使用正在执行的程序集的现有公钥
  • 最后一种方式可能不是最好的方法,因为您可能想要区分使用"插件"键签名的程序集与使用常规键签名的程序集)

例:

public static StrongName GetStrongName(Assembly assembly)
{
    if(assembly == null)
        throw new ArgumentNullException("assembly");
    AssemblyName assemblyName = assembly.GetName();

    // get the public key blob
    byte[] publicKey = assemblyName.GetPublicKey();
    if(publicKey == null || publicKey.Length == 0)
       throw new InvalidOperationException( String.Format("{0} is not strongly named", assembly));

    StrongNamePublicKeyBlob keyBlob = new StrongNamePublicKeyBlob(publicKey);

    // create the StrongName
    return new StrongName(keyBlob, assemblyName.Name, assemblyName.Version);
}


// load the assembly:
Assembly asm = Assembly.LoadFile(path);
StrongName sn = GetStrongName(asm);

// at this point
// A: assembly is loaded
// B: assembly is signed
// C: we're reasonably certain the assembly has not been tampered with
// (the mechanism for this check, and it's weaknesses, are documented elsewhere)

// all that remains is to compare the assembly's public key with 
// a copy you've stored for this purpose, let's use the executing assembly's strong name
StrongName mySn = GetStrongName(Assembly.GetExecutingAssembly());

// if the sn does not match, put this loaded assembly in jail
if (mySn.PublicKey!=sn.PublicKey)
    return false;
Run Code Online (Sandbox Code Playgroud)

注意:代码尚未经过测试或编译,可能包含语法错误.