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介面
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鏈的構造
歡迎關注我的公眾號,同步更新喔