不能用“并发属性封装”防止核心类被篡改,因其仅保障多线程状态可见性与原子性,无法校验字节码完整性;真正有效的防护必须在ClassLoader.defineClass()调用前完成指纹比对,实现事前防御。

不能用“并发属性封装”来防止核心类被外部脚本篡改。这个说法混淆了技术本质:并发(如 volatile、AtomicReference、synchronized)解决的是多线程读写可见性与原子性问题,不是完整性校验手段;而防篡改的关键,在于确保类字节码在加载进 JVM 前未被替换,与是否并发无关。
真正起效的防护必须卡在类加载前
Java 中类是否被篡改,决定性时刻是 ClassLoader.defineClass() 被调用的那一瞬间。在此之前完成指纹比对,才叫“事前防御”。之后任何操作——包括反射读取、异步校验、属性标记——都属于“事后补救”,攻击者早已执行完敏感逻辑或屏蔽校验本身。
- 自定义
findClass()方法,从可信路径(如签名 JAR 内部)读取字节流 - 一次性全量读入
byte[],计算 SHA-256 或 SM3 摘要 - 与启动时预置的指纹比对,不一致立即抛
SecurityException - 仅当通过,才调用
defineClass(),否则加载中断
“并发属性”只能辅助,不能替代校验逻辑
比如用 volatile boolean verified 标记某个类已校验过,或用 AtomicBoolean 控制校验开关——这些只是状态同步工具,本身不验证内容。若校验逻辑被绕过或篡改,再“并发安全”的标记也毫无意义。
-
volatile不防字节码替换,只保证变量修改对其他线程可见 -
AtomicReference<byte[]>可以安全交换字节数组,但不校验数组内容是否真实 - 把校验结果存在并发容器里,反而增加被 Hook 或覆盖的风险
更可靠的做法是源头可信 + 流程强制
不要依赖运行时动态行为,而是把校验固化在构建与加载环节:
- 构建时用 Maven 插件生成每个核心类的哈希,写入
META-INF/MANIFEST.MF - 类加载器解析 MANIFEST 中对应项,比对失败直接拒载
- 启用 JVM 签名验证:
-Djdk.jar.disabledAlgorithms=配合jarsigner -verify - 关键类加
@Deprecated或自定义注解(仅作标识,不用于运行时校验)
所谓“并发属性封装动态比对”,本质上是把一个确定性安全动作,包装成不确定的运行时行为——这不仅没增强防护,反而引入调度延迟、竞态风险和绕过路径。防篡改不需要“动态”,需要的是“确定、即时、不可跳过”。

















