Security Model - HimxhMC/HimDSL GitHub Wiki
HimDSL 安全模型完整参考
HimDSL Security Model — Complete Reference
一、总体设计哲学
1. Overall Design Philosophy
安全模型遵循三条原则:默认可用、显式禁止、出错即止。 The security model follows three principles: usable by default, deny explicitly, stop on error.
默认可用意味着不需要为每个功能写"允许规则"。 Usable by default means you don't write "allow rules" for every feature.
显式禁止意味着只有明确列出的危险项会被拦截。 Deny explicitly means only clearly listed dangerous items are blocked.
出错即止意味着任何权限拒绝或运行异常都会立刻中止脚本并清理资源。 Stop on error means any permission denial or runtime exception immediately aborts the script and cleans up resources.
二、三级权限模型
2. Three-Tier Permission Model
系统定义三个安全级别:trusted、normal、sandbox。 The system defines three security levels: trusted, normal, sandbox.
trusted 完全信任,等同插件自身权限,绕过全部黑名单检查。 trusted is fully trusted, equivalent to the plugin's own privileges, bypassing all blacklist checks.
normal 是默认级别,允许日常功能,但禁止逃逸型操作。 normal is the default level, allowing daily features but forbidding escape-type operations.
sandbox 最小权限,只读加纯计算加输出,无任何副作用。 sandbox has minimal privileges: read-only plus pure computation plus output, with no side effects.
默认级别在配置文件中由 security.default-level 指定,初始值为 normal。
The default level is set by security.default-level in the config file, initially normal.
三、能力模型
3. Capability Model
每个可能产生副作用的操作被抽象为一个能力(Capability)。 Every operation that may have side effects is abstracted as a Capability.
每个级别拥有一个能力集合,配置可自由调整。 Each level has a set of capabilities, fully configurable.
能力分为八类:文件系统、执行与调度、类加载与反射、Bukkit 副作用、GUI 与事件、选择器、外部桥、其他。 Capabilities fall into eight categories: filesystem, execution and scheduling, class loading and reflection, Bukkit side effects, GUI and events, selectors, external bridges, and others.
3.1 文件系统类
3.1 Filesystem
FS_READ 允许读取文件。 FS_READ allows reading files.
FS_WRITE 允许写入或创建文件。 FS_WRITE allows writing or creating files.
FS_DELETE 允许删除文件。 FS_DELETE allows deleting files.
FS_ABSOLUTE 允许使用绝对路径。 FS_ABSOLUTE allows using absolute paths.
3.2 执行与调度类
3.2 Execution and Scheduling
CMD_CONSOLE 允许以控制台身份执行命令。 CMD_CONSOLE allows executing commands as the console.
CMD_PLAYER 允许以玩家身份执行命令。 CMD_PLAYER allows executing commands as a player.
SCHEDULER 允许创建定时任务和延迟任务。 SCHEDULER allows creating scheduled and delayed tasks.
SLEEP 允许脚本休眠,且受时长上限约束。 SLEEP allows the script to sleep, subject to a duration limit.
3.3 类加载与反射类
3.3 Class Loading and Reflection
CLASS_LOAD 允许解析和加载类。 CLASS_LOAD allows resolving and loading classes.
NEW_OBJECT 允许通过 new 创建对象。
NEW_OBJECT allows creating objects via new.
STATIC_ACCESS 允许访问静态字段和静态方法。 STATIC_ACCESS allows accessing static fields and static methods.
3.4 Bukkit 副作用类
3.4 Bukkit Side Effects
WORLD_WRITE 允许修改世界方块。 WORLD_WRITE allows modifying world blocks.
ENTITY_MODIFY 允许修改实体状态。 ENTITY_MODIFY allows modifying entity state.
INVENTORY_MODIFY 允许修改玩家或容器背包。 INVENTORY_MODIFY allows modifying player or container inventories.
PLAYER_ADMIN 允许执行管理员级玩家操作,例如 op、kick、ban。 PLAYER_ADMIN allows admin-level player operations such as op, kick, ban.
3.5 GUI 与事件类
3.5 GUI and Events
GUI 允许创建和操作箱子界面。 GUI allows creating and manipulating chest GUIs.
EVENT_HANDLER 允许注册事件监听器。 EVENT_HANDLER allows registering event listeners.
3.6 选择器类
3.6 Selectors
SELECTOR_GLOBAL 允许使用 @a / @e / @p / @r 等全局选择器。 SELECTOR_GLOBAL allows using global selectors like @a / @e / @p / @r.
@s(当前触发玩家)不需要此能力。 @s (the current trigger player) does not require this capability.
3.7 外部桥接类
3.7 External Bridges
PAPI_READ 允许读取 PlaceholderAPI 变量。 PAPI_READ allows reading PlaceholderAPI variables.
PAPI_REGISTER 允许注册和修改本地变量。 PAPI_REGISTER allows registering and modifying local variables.
BOSS_API 允许调用 HimDungeons 的 Boss 接口。 BOSS_API allows calling HimDungeons' Boss API.
四、各级别默认能力矩阵
4. Default Capability Matrix
trusted 拥有全部能力。 trusted has all capabilities.
normal 拥有:FS_READ、FS_WRITE、CMD_PLAYER、SCHEDULER、SLEEP、CLASS_LOAD、NEW_OBJECT、STATIC_ACCESS、WORLD_WRITE、ENTITY_MODIFY、INVENTORY_MODIFY、GUI、EVENT_HANDLER、SELECTOR_GLOBAL、PAPI_READ、PAPI_REGISTER、BOSS_API。 normal has: FS_READ, FS_WRITE, CMD_PLAYER, SCHEDULER, SLEEP, CLASS_LOAD, NEW_OBJECT, STATIC_ACCESS, WORLD_WRITE, ENTITY_MODIFY, INVENTORY_MODIFY, GUI, EVENT_HANDLER, SELECTOR_GLOBAL, PAPI_READ, PAPI_REGISTER, BOSS_API.
normal 不拥有:FS_DELETE、FS_ABSOLUTE、CMD_CONSOLE、PLAYER_ADMIN。 normal does not have: FS_DELETE, FS_ABSOLUTE, CMD_CONSOLE, PLAYER_ADMIN.
sandbox 仅拥有:FS_READ、SLEEP、PAPI_READ。 sandbox only has: FS_READ, SLEEP, PAPI_READ.
sandbox 明确禁止:EVENT_HANDLER、GUI、SCHEDULER、CLASS_LOAD、NEW_OBJECT、STATIC_ACCESS、CMD_PLAYER、CMD_CONSOLE、全局选择器、文件写入。 sandbox explicitly forbids: EVENT_HANDLER, GUI, SCHEDULER, CLASS_LOAD, NEW_OBJECT, STATIC_ACCESS, CMD_PLAYER, CMD_CONSOLE, global selectors, and file writes.
五、黑名单策略
5. Blacklist Policy
除能力模型外,还有一层黑名单,用于拦截反射逃逸链。 Beyond the capability model, there is a blacklist layer to block reflection escape chains.
黑名单不区分能力,只要命中就拒绝,除非级别为 trusted。 The blacklist is independent of capabilities: any hit is denied unless the level is trusted.
黑名单分三类:精确类名、类名前缀、方法名。 The blacklist has three kinds: exact class names, class name prefixes, method names.
5.1 默认类黑名单(精确)
5.1 Default Class Blacklist (Exact)
java.lang.Runtime java.lang.Runtime
java.lang.ProcessBuilder java.lang.ProcessBuilder
java.lang.Process java.lang.Process
java.lang.ClassLoader java.lang.ClassLoader
java.lang.invoke.MethodHandle java.lang.invoke.MethodHandle
java.lang.invoke.MethodHandles java.lang.invoke.MethodHandles
java.lang.invoke.VarHandle java.lang.invoke.VarHandle
sun.misc.Unsafe sun.misc.Unsafe
jdk.internal.misc.Unsafe jdk.internal.misc.Unsafe
5.2 默认类前缀黑名单
5.2 Default Class Prefix Blacklist
sun. sun.
com.sun. com.sun.
jdk.internal. jdk.internal.
5.3 默认方法名黑名单
5.3 Default Method Name Blacklist
反射链入口:getClass、forName、loadClass。 Reflection chain entry points: getClass, forName, loadClass.
成员查找:getMethod、getDeclaredMethod、getMethods、getDeclaredMethods。 Member lookup: getMethod, getDeclaredMethod, getMethods, getDeclaredMethods.
字段查找:getField、getDeclaredField、getFields、getDeclaredFields。 Field lookup: getField, getDeclaredField, getFields, getDeclaredFields.
构造查找:getConstructor、getDeclaredConstructor、getConstructors、getDeclaredConstructors。 Constructor lookup: getConstructor, getDeclaredConstructor, getConstructors, getDeclaredConstructors.
反射执行:setAccessible、invoke、newInstance。 Reflective execution: setAccessible, invoke, newInstance.
进程与 JVM:exec、exit、halt、getRuntime、setSecurityManager。 Process and JVM: exec, exit, halt, getRuntime, setSecurityManager.
5.4 为什么用黑名单
5.4 Why a Blacklist
白名单要求服主枚举"允许访问的包",非常繁琐且容易遗漏。 A whitelist requires server owners to enumerate allowed packages, which is tedious and error-prone.
黑名单让服主只关注真正危险的东西,符合"默认信任 + 显式红线"的运维直觉。 A blacklist focuses on truly dangerous items, matching the "trust by default + explicit red lines" operations mindset.
新增限制只需一行配置,不需要维护一个不断膨胀的白名单。 Adding a restriction takes one config line and does not require maintaining an ever-growing whitelist.
六、级别判定机制
6. Level Resolution
脚本级别由相对路径决定,不硬编码在脚本里。 Script level is determined by relative path, not hardcoded in the script.
配置文件中的 security.per-script 是一组 glob 规则。
security.per-script in the config file is a list of glob rules.
规则从上到下匹配,第一个命中的生效。 Rules are matched top-to-bottom; the first hit wins.
支持 ** 匹配跨目录,* 匹配单段,普通字符字面匹配。
Supports ** for cross-directory, * for a single segment, and literal matching for normal characters.
未被任何规则命中时使用 default-level。
If no rule matches, default-level is used.
匹配过程跨平台,Windows 与 Linux 行为一致。 Matching is cross-platform: Windows and Linux behave identically.
七、拦截点
7. Interception Points
所有危险操作在调用发生的那一刻检查,不在语法层过滤。 All dangerous operations are checked at call time, not filtered at the grammar layer.
语法层过滤挡不住反射逃逸,必须在运行时拦截。 Grammar-layer filtering cannot stop reflection escapes; runtime interception is mandatory.
拦截点覆盖以下位置: The following locations are intercepted:
能力检查:BuiltinFunctions 的各 case 入口。 Capability checks: each case entry in BuiltinFunctions.
类黑名单:类解析、静态方法、静态字段、构造器。 Class blacklist: class resolution, static methods, static fields, constructors.
方法名黑名单:所有对象方法调用、静态方法调用、枚举静态方法。 Method name blacklist: all object method calls, static method calls, and enum static methods.
选择器检查:任何非 @s 的选择器。 Selector check: any selector that is not @s.
GUI 检查:GuiRef 构造与 newExpr 中的 GUI / GUISlot。 GUI check: GuiRef construction and GUI / GUISlot in newExpr.
事件检查:EventManager 的 enableFunction。 Event check: EventManager's enableFunction.
调度检查:HimDSLRuntime 的 startFunction。 Scheduler check: HimDSLRuntime's startFunction.
八、上下文传播
8. Context Propagation
安全上下文使用 ThreadLocal 保存,包含脚本 ID 与级别。 The security context uses a ThreadLocal holding script ID and level.
异步或延迟执行时,上下文必须显式传播,否则检查会失效。 During async or delayed execution, the context must be explicitly propagated, otherwise checks silently fail.
系统在所有跨线程路径上都做了捕获与恢复: The system captures and restores the context on all cross-thread paths:
EntityRef.runSync 派发主线程任务时。 When EntityRef.runSync dispatches to the main thread.
BukkitRunnable 定时任务的每次执行。 On each execution of a BukkitRunnable scheduled task.
EventManager 注册的事件执行器。 In event executors registered by EventManager.
LambdaValue.adaptTo 生成的函数式接口实例。 In functional interface instances produced by LambdaValue.adaptTo.
每次脚本运行开始时设置,结束时清除。 The context is set at script start and cleared at script end.
九、异常中断与资源清理
9. Abort and Cleanup
任何未捕获异常都会触发三件事:WARNING 日志、立即中止脚本、清理该脚本注册的所有资源。 Any uncaught exception triggers three things: a WARNING log, immediate script abort, and cleanup of all resources registered by that script.
被清理的资源包括定时任务、事件监听器、GUI 回调、未关闭的文件句柄。 Cleaned resources include scheduled tasks, event listeners, GUI callbacks, and unclosed file handles.
清理仅针对出错脚本自身,不影响其他脚本或服务器既有任务。 Cleanup only affects the failing script, not other scripts or existing server tasks.
每个脚本以相对路径为 ID,拥有独立的资源域。 Each script is identified by its relative path and has an independent resource scope.
脚本重跑时,旧资源按 ID 清理,避免定时任务翻倍。 When a script re-runs, old resources are cleaned by ID, preventing scheduled task duplication.
十、特殊豁免规则
10. Special Exemption Rules
10.1 枚举常量豁免
10.1 Enum Constant Exemption
读取枚举常量和调用 values / valueOf 不检查 CLASS_LOAD。 Reading enum constants and calling values / valueOf does not check CLASS_LOAD.
原因:GameMode.CREATIVE 这类常量本身无副作用。
Reason: constants like GameMode.CREATIVE have no side effects.
这保证 sandbox 脚本仍能使用 Bukkit 的枚举。 This ensures sandbox scripts can still use Bukkit enums.
10.2 @s 选择器豁免
10.2 @s Selector Exemption
@s 表示"当前触发玩家",不检查 SELECTOR_GLOBAL。 @s means "current trigger player", and does not check SELECTOR_GLOBAL.
这样即使 sandbox 脚本也能对事件来源玩家做出响应。 This allows even sandbox scripts to respond to the event source player.
10.3 PermissionDeniedException 不可捕获
10.3 PermissionDeniedException Cannot Be Caught
权限拒绝异常无法被脚本的 try-catch 捕获。 Permission denial exceptions cannot be caught by script try-catch.
这是为了防止脚本吞掉权限日志,静默绕过审计。 This prevents scripts from swallowing permission logs and silently bypassing audits.
finally 块依然会执行,但 catch 块被跳过。 The finally block still runs, but the catch block is skipped.
10.4 trusted 绕过黑名单
10.4 trusted Bypasses the Blacklist
trusted 级别的脚本跳过全部黑名单检查。 Scripts at the trusted level skip all blacklist checks.
但能力检查依然生效,如果某个能力被手动从 trusted 中移除。 Capability checks still apply, however, if a capability is manually removed from trusted.
十一、审计模式
11. Audit Mode
配置项 security.audit-only: true 开启审计模式。
The config item security.audit-only: true enables audit mode.
审计模式下不真正拦截,只记录一条 WARNING。 Audit mode does not actually deny; it only logs a WARNING.
同一脚本与同一能力的组合只警告一次,避免刷屏。 The same script-and-capability combination warns only once, avoiding log spam.
推荐在部署前先开审计模式跑一段时间,摸清脚本实际所需能力。 It is recommended to enable audit mode before deployment to discover the actual capabilities scripts need.
十二、默认配置文件
12. Default Config File
security:
default-level: normal
audit-only: false
sleep-max-ms: 900000
blacklist-classes:
- java.lang.Runtime
- java.lang.ProcessBuilder
- java.lang.Process
- java.lang.ClassLoader
- java.lang.invoke.MethodHandle
- java.lang.invoke.MethodHandles
- java.lang.invoke.VarHandle
- sun.misc.Unsafe
- jdk.internal.misc.Unsafe
blacklist-class-prefixes:
- sun.
- com.sun.
- jdk.internal.
blacklist-methods:
- getClass
- forName
- loadClass
- getMethod
- getDeclaredMethod
- getMethods
- getDeclaredMethods
- getField
- getDeclaredField
- getFields
- getDeclaredFields
- getConstructor
- getDeclaredConstructor
- getConstructors
- getDeclaredConstructors
- setAccessible
- invoke
- newInstance
- exec
- exit
- halt
- getRuntime
- setSecurityManager
per-script:
admin/**: trusted
public/**: sandbox
levels:
trusted:
capabilities: ["*"]
normal:
capabilities:
- FS_READ
- FS_WRITE
- CMD_PLAYER
- SCHEDULER
- SLEEP
- CLASS_LOAD
- NEW_OBJECT
- STATIC_ACCESS
- WORLD_WRITE
- ENTITY_MODIFY
- INVENTORY_MODIFY
- GUI
- EVENT_HANDLER
- SELECTOR_GLOBAL
- PAPI_READ
- PAPI_REGISTER
- BOSS_API
sandbox:
capabilities:
- FS_READ
- SLEEP
- PAPI_READ
十三、运维建议
13. Operations Recommendations
新部署服务器先开审计模式,观察一周。 For new deployments, enable audit mode first and observe for a week.
第三方来源的脚本一律放 public/ 或单独目录并设 sandbox。 Third-party scripts should always go in public/ or a dedicated directory configured as sandbox.
服务器核心脚本放 admin/,只授予 trusted 给内部开发者。 Server core scripts go in admin/; grant trusted only to internal developers.
定期检查日志中出现的"权限被拒绝"记录。 Periodically check the logs for "permission denied" entries.
新增危险类或方法到黑名单时,优先加到方法名黑名单。 When adding new dangerous classes or methods, prefer the method name blacklist.
如果某个能力从未被任何脚本使用,考虑从 normal 中移除。 If a capability is never used by any script, consider removing it from normal.
备份 config.yml,安全策略调整应记录变更原因与时间。 Back up config.yml, and record the reason and time for every security policy change.
十四、常见逃逸路径与拦截点对照
14. Common Escape Paths vs Interception Points
Runtime.getRuntime().exit() → 类黑名单 java.lang.Runtime。 Runtime.getRuntime().exit() → class blacklist java.lang.Runtime.
new ProcessBuilder("cmd").start() → 类黑名单与 NEW_OBJECT 能力。 new ProcessBuilder("cmd").start() → class blacklist and NEW_OBJECT capability.
obj.getClass().forName(...) → 方法名黑名单 getClass 与 forName。 obj.getClass().forName(...) → method name blacklist getClass and forName.
cls.getMethod("x").invoke(...) → 方法名黑名单 getMethod 与 invoke。 cls.getMethod("x").invoke(...) → method name blacklist getMethod and invoke.
System.setSecurityManager(null) → 方法名黑名单 setSecurityManager。 System.setSecurityManager(null) → method name blacklist setSecurityManager.
ClassLoader.loadClass(...) → 类黑名单与方法名黑名单。 ClassLoader.loadClass(...) → class and method name blacklists.
sun.misc.Unsafe → 类黑名单与前缀黑名单。 sun.misc.Unsafe → class blacklist and prefix blacklist.
lambda 中的危险调用 → 上下文传播 + 以上全部拦截。 Dangerous calls inside lambda → context propagation plus all of the above.
十五、模型边界与已知限制
15. Model Boundaries and Known Limitations
安全模型只覆盖脚本可见的调用路径,不覆盖 Bukkit 自身的缺陷。 The model covers only script-visible call paths, not Bukkit's own vulnerabilities.
同一 JVM 内的其他插件若已提权,不在本模型范围内。 If other plugins in the same JVM are already privileged, they are outside this model.
反射链的防护依赖方法名黑名单,若 Bukkit 引入新反射入口需要更新。 Reflection protection relies on the method name blacklist; new reflection entry points in Bukkit will require updates.
沙箱不隔离内存或 CPU 使用,长期运行的死循环仍可能卡主线程。 The sandbox does not isolate memory or CPU usage; a long-running infinite loop can still block the main thread.
建议配合服务器自身的 watchdog 与性能监控一起使用。 Use together with the server's own watchdog and performance monitoring.
十六、总结
16. Summary
安全模型由三部分组成:三级权限、能力清单、黑名单。 The security model consists of three parts: three tiers, a capability list, and a blacklist.
能力模型控制"这类操作能不能做",黑名单控制"这个具体对象能不能碰"。 The capability model controls "can this kind of operation be done"; the blacklist controls "can this specific object be touched".
两者叠加,再加上跨线程的上下文传播与出错清理,构成完整的防御。 Together, plus cross-thread context propagation and error cleanup, they form a complete defense.
配置全部集中在 config.yml 的 security 节,运维友好。 All configuration is centralized in the security section of config.yml, operations-friendly.