1. 程式人生 > 其它 >JAVA安全基礎之代理模式(二)

JAVA安全基礎之代理模式(二)

上篇講到靜態代理模式,這時候我們發現,一個代理類只能為一個類服務,如果需要代理的類很多,那麼就需要編寫大量的代理類,比較繁瑣。所以就有了動態代理

動態代理

動態代理的代理類,是在記憶體中構建代理物件,從而實現對目標物件的代理功能。

在這裡我們需要知道兩個類:1.InvocationHandler(介面)、2.Proxy(類)

來看下具體使用步驟

1.(介面)建立Person介面:

public interface Person {
    //上交班費
    void giveMoney();
}

2.(被代理類)Student類實現了Person介面。Student可以具體實施上交班費的動作。

public class Student implements Person{
    private String name;

    public Student(String name) {
        this.name = name;
    }

    @Override
    public void giveMoney() {
        System.out.println(name + "上交了班費");
    }

    public String getName() {
        return name;
    }
}

3.(InvocationHandler類)建立一個物件ProxyHandler,實現了InvocationHandler介面

。也要持有一個Student類物件(這裡換成了Object)。他可以通過反射來執行Student類的giveMoney()方法

public class ProxyHandler implements InvocationHandler {
	//這裡寫的是Object類
    private Object object;

    public ProxyHandler(Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("--------------begin-------------");
        method.invoke(object, args);
        System.out.println("--------------end-------------");
        return null;
    }
}

InvocationHandler物件可以通過Proxy.newProxyInstance()來獲得代理類物件,下面的proxyStudent就是代理類物件。

Person proxyStudent = (Person) Proxy.newProxyInstance(Student.class.getClassLoader(), Student.class.getInterfaces(), proxyHandler);

1.被動態代理的物件呼叫任意方法都會通過對應InvocationHandler的invoke方法觸發

2.代理物件的每個執行方法都會去執行到InvocationHandler中的invoke方法

4.測試動態代理:

public class ProxyTest {
    public static void main(String[] args) {
        //例項化被動態代理的物件
        Student student = new Student("xiaoming");
        //例項化實現了InvocationHandler介面的類
        InvocationHandler proxyHandler = new ProxyHandler(student);
        //建立代理類proxyStudent
        Person proxyStudent = (Person) Proxy.newProxyInstance(Student.class.getClassLoader(), Student.class.getInterfaces(), proxyHandler);
        //代理類物件呼叫被代理類的方法
        proxyStudent.giveMoney();
    }
}

執行結果:

加入來了個新的代理類mon

public interface Mom {
    void here();
}
public class MomImpl implements Mom {
    @Override
    public void here() {
        System.out.println("mom來了");
    }
}

測試類應該這麼寫:

public class ProxyTest {
    public static void main(String[] args) {

        Student student = new Student("xiaoming");
        MomImpl mom = new MomImpl();

        InvocationHandler proxyHandler = new ProxyHandler(student);
        InvocationHandler momHandler = new ProxyHandler(mom);

        Person proxyStudent = (Person) Proxy.newProxyInstance(Student.class.getClassLoader(), Student.class.getInterfaces(), proxyHandler);
        Mom proxyMon = (Mom) Proxy.newProxyInstance(MomImpl.class.getClassLoader(), MomImpl.class.getInterfaces(), momHandler);

        proxyStudent.giveMoney();
        proxyMon.here();
    }
}

執行結果:

我們來用ysoserial中的CC1鏈來理解,是怎麼利用動態代理特性來構造payload的

在CC1中,利用了動態代理特性來構造了攻擊payload,我們來看下實現過程。

1.AnnotationInvocationHandler為一個InvocationHandler

2.AnnotationInvocationHandler建構函式傳入了被代理物件var2,賦值給了this.memberValues

根據前面說的,被動態代理的物件呼叫任意方法都會通過對應InvocationHandler的invoke方法觸發

也就是說this.memberValues呼叫方法會呼叫AnnotationInvocationHandler的invoke方法

【AnnotationInvocationHandler的invoke方法】

在AnnotationInvocationHandler的readObject方法中呼叫了this.memberValues的方法

所以會轉到AnnotationInvocationHandler的invoke方法

往下看到78行,在AnnotationInvocationHandler#invoke方法中,this.memberValues呼叫了get方法。

而在CC1中,AnnotationInvocationHandler構造方法var2引數傳入的是LazyMap物件,所以this.memberValues = LazyMap

進而會去呼叫LazyMap.get方法,完成cc鏈的構造

歡迎關注我的公眾號,同步更新喔