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

Java终结器安全问题解析及攻击代码演示请求

关于Finalizer攻击的理解确认与代码演示

你的理解完全正确

你总结的4点核心问题,正是终结器被废弃以及finalizer攻击的关键原因:

  • 终结器具有不确定性:其执行时间由GC决定,无法预测,可能导致资源泄露或逻辑异常
  • 恶意子类可在部分构造的损坏父类对象上运行其终结器方法:父类构造失败时,子类的终结器仍可能被触发
  • 将损坏对象的引用存入静态字段会阻止JVM垃圾回收:静态字段属于类级别,不会被GC回收,从而保留了本应销毁的对象
  • 攻击者可利用本应销毁的对象实施操作,引发安全漏洞:未完全初始化的对象可能执行敏感逻辑,破坏系统安全性

Finalizer攻击代码演示

基于你提供的类结构,我们改造后实现完整的攻击场景:

存在安全风险的父类

/** 存在安全风险的父类 */
public class DemoSecurityProblem {
    public DemoSecurityProblem() {
        // 模拟构造过程中抛出异常,导致对象未完全初始化
        throw new RuntimeException("构造失败,对象未完全初始化");
    }

    // 假设的敏感业务方法,仅允许完全初始化的对象调用
    public void doSensitiveOperation() {
        System.out.println("执行敏感操作:" + this);
    }
}

恶意子类

public class MaliciousSubClass extends DemoSecurityProblem {
    // 静态字段保存泄漏的未初始化对象,阻止GC回收
    private static DemoSecurityProblem leakedInstance;

    public MaliciousSubClass() {
        // 父类构造抛出异常,子类构造流程中断,但对象已部分创建
    }

    @Override
    protected void finalize() throws Throwable {
        // 将当前未完全初始化的对象存入静态字段
        leakedInstance = this;
        System.out.println("终结器被调用,已泄漏未初始化对象");
        super.finalize();
    }

    // 攻击者利用泄漏对象的入口方法
    public static void exploit() {
        if (leakedInstance != null) {
            System.out.println("利用泄漏的未初始化对象:");
            leakedInstance.doSensitiveOperation();
        }
    }
}

攻击测试类

public class FinalizerAttackDemo {
    public static void main(String[] args) throws InterruptedException {
        try {
            // 尝试创建子类对象,触发父类构造异常
            new MaliciousSubClass();
        } catch (RuntimeException e) {
            System.out.println("捕获构造异常:" + e.getMessage());
        }

        // 触发GC,促使终结器执行
        System.gc();
        // 等待终结器线程完成(实际中终结器执行时间不确定,此处用sleep模拟)
        Thread.sleep(1000);

        // 执行攻击逻辑
        MaliciousSubClass.exploit();
    }
}

代码执行流程说明

  1. 当尝试创建MaliciousSubClass实例时,父类构造抛出异常,对象未完全初始化,按正常逻辑应被GC回收。
  2. GC触发后,JVM发现该对象未被任何可达引用指向,准备回收时调用子类重写的finalize方法,将对象存入静态字段leakedInstance,使其成为可达状态,阻止GC回收。
  3. 攻击者通过exploit方法获取该未初始化对象,调用其敏感方法,实现攻击。

防御方式验证

如果将父类声明为final:

public final class DemoSecurityProblem {
    // 原有代码不变
}

此时MaliciousSubClass无法继承该类,也就无法重写finalize方法,从根源上避免了这类攻击,这也印证了《Effective Java》中提到的final类免疫finalizer攻击的结论。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 16:30:45