You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在ASP.NET Core中控制上传插件DLL的.NET API访问权限?

控制外部.NET DLL的API可访问性与ASP.NET Core插件安全限制

Great question—this is a critical security concern when dealing with untrusted plugins in ASP.NET Core. Let’s break this down into actionable, secure solutions:

1. 基础控制:加载外部DLL时的权限约束

When loading external assemblies, you have two primary levers to control API accessibility upfront:

1.1 基于权限集的约束(.NET Framework兼容,.NET Core有限支持)

For .NET Framework, you can use Code Access Security (CAS) to define a restricted permission set for untrusted assemblies. While CAS is deprecated in .NET Core, you can still use similar patterns with PermissionSet for limited scenarios:

// Create a permission set with ONLY necessary permissions
var restrictedPermissions = new PermissionSet(PermissionState.None);
// Grant execution permission (required to run the plugin)
restrictedPermissions.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
// Optionally grant access to a specific, isolated directory (if needed)
restrictedPermissions.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read, @"C:\AllowedPluginData"));

// Use evidence to enforce the permission set
var evidence = new Evidence();
evidence.AddHostEvidence(new Zone(SecurityZone.Internet)); // Mimic untrusted zone constraints

// Load the assembly with the restricted permissions
var pluginAssembly = Assembly.LoadFrom("UntrustedPlugin.dll", evidence, restrictedPermissions);

1.2 强命名验证

If you work with trusted plugin developers, require them to sign their assemblies with a strong name. You can validate the assembly's public key token before loading to ensure it comes from a trusted source:

var pluginAssemblyName = AssemblyName.GetAssemblyName("TrustedPlugin.dll");
// Replace with your trusted public key token
var trustedToken = new byte[] { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };

if (!pluginAssemblyName.GetPublicKeyToken().SequenceEqual(trustedToken))
{
    throw new InvalidOperationException("Plugin is not signed with a trusted key.");
}

var trustedAssembly = Assembly.Load(pluginAssemblyName);

2. ASP.NET Core:阻止插件访问敏感API(比如System.IO)

.NET Core and .NET 5+ replace CAS with more flexible isolation mechanisms. Here are the most reliable approaches for untrusted plugins:

2.1 自定义AssemblyLoadContext(核心隔离手段)

Create a dedicated AssemblyLoadContext (ALC) to load plugins, and explicitly block access to sensitive system assemblies. This prevents the plugin from resolving and using APIs from forbidden assemblies:

public class IsolatedPluginLoadContext : AssemblyLoadContext
{
    private readonly AssemblyDependencyResolver _resolver;
    // List of system assemblies to block
    private readonly HashSet<string> _forbiddenAssemblies = new() 
    { 
        "System.IO", "System.Security", "System.Net", "System.Diagnostics.Process" 
    };

    public IsolatedPluginLoadContext(string pluginPath) : base(isCollectible: true)
    {
        _resolver = new AssemblyDependencyResolver(pluginPath);
    }

    protected override Assembly? Load(AssemblyName assemblyName)
    {
        // Block forbidden system assemblies entirely
        if (_forbiddenAssemblies.Contains(assemblyName.Name))
        {
            return null; // Returns null to fail the assembly resolution
        }

        // Only load assemblies from the plugin's directory (prevents loading malicious external DLLs)
        var assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
        return assemblyPath != null ? LoadFromAssemblyPath(assemblyPath) : null;
    }

    protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
    {
        // Block all unmanaged DLLs to prevent native code execution
        return IntPtr.Zero;
    }
}

To use this ALC:

var pluginPath = Path.Combine(Environment.ContentRootPath, "Plugins", "UserUploadedPlugin.dll");
using var pluginContext = new IsolatedPluginLoadContext(pluginPath);
var pluginAssembly = pluginContext.LoadFromAssemblyPath(pluginPath);

2.2 静态代码分析(Pre-upload validation)

Before even loading the plugin, scan its metadata to detect references to sensitive APIs. This lets you reject malicious plugins upfront without executing any code. Use System.Reflection.Metadata for lightweight, safe analysis:

public bool IsPluginSafe(string pluginFilePath)
{
    using var fileStream = File.OpenRead(pluginFilePath);
    var readerProvider = MetadataReaderProvider.FromPortableExecutableStream(fileStream);
    var metadataReader = readerProvider.GetMetadataReader();

    // Define sensitive types and methods to block
    var forbiddenTypes = new HashSet<string> { "System.IO.File", "System.IO.Directory" };
    var forbiddenMethods = new HashSet<string> { "ReadAllText", "WriteAllText", "Delete", "CreateDirectory" };

    foreach (var methodDefHandle in metadataReader.MethodDefinitions)
    {
        var methodDef = metadataReader.GetMethodDefinition(methodDefHandle);
        var declaringType = metadataReader.GetTypeDefinition(methodDef.GetDeclaringType());
        var typeName = metadataReader.GetString(declaringType.Name);
        var methodName = metadataReader.GetString(methodDef.Name);

        // Check if the plugin defines a method that directly uses sensitive APIs
        if (forbiddenTypes.Contains(typeName) && forbiddenMethods.Contains(methodName))
        {
            return false;
        }

        // Check if the method calls sensitive APIs (via call/callvirt instructions)
        if (methodDef.GetMethodBody().HasValue)
        {
            var bodyReader = methodDef.GetMethodBody().Value.GetBlobReader(metadataReader);
            while (bodyReader.RemainingBytes > 0)
            {
                var opcode = bodyReader.ReadByte();
                // Look for method call opcodes (0x28 = call, 0x6F = callvirt)
                if (opcode is 0x28 or 0x6F)
                {
                    var calledMethodHandle = bodyReader.ReadMethodHandle();
                    var calledMethod = metadataReader.GetMethodDefinition(calledMethodHandle);
                    var calledTypeName = metadataReader.GetString(metadataReader.GetTypeDefinition(calledMethod.GetDeclaringType()).Name);
                    var calledMethodName = metadataReader.GetString(calledMethod.Name);

                    if (forbiddenTypes.Contains(calledTypeName) && forbiddenMethods.Contains(calledMethodName))
                    {
                        return false;
                    }
                }
            }
        }
    }
    return true;
}

Run this check immediately after a user uploads a plugin—reject any DLL that fails the scan.

2.3 进程级沙箱(Ultimate Isolation)

For maximum security, run plugins in a separate, low-privilege process. Use IPC (like gRPC or named pipes) to communicate between the ASP.NET Core host and the plugin process. This way:

  • Malicious code can’t access the host process’s memory or resources
  • You can restrict the plugin process’s OS-level permissions (e.g., run as a low-privilege user)
  • Plugin crashes won’t take down the main web app

3. Additional Hardening Tips

  • Limit execution time: Use CancellationToken to terminate long-running plugin code and prevent denial-of-service attacks.
  • Monitor resource usage: Track CPU and memory consumption of plugins to detect abnormal behavior.
  • Audit logs: Log all plugin actions (API calls, resource access) for post-incident analysis.
  • Code signing: Require plugins to be signed with a trusted certificate to add an extra layer of trust.

内容的提问来源于stack exchange,提问作者Alsein

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:20:29