安全開發Java動態代理
關于安全開發的一些思考
之前面試某寶的時候,某人問過我,如果解決開發不懂安全的問題,就比如說SSRF,XEE這樣的漏洞,如果一旦發生,應該如果立刻去響應,并幫助開發人員修復漏洞,難道寫一個jar包?然后丟給數以百計的業務去調用?還是你去手把手的去教給開發,應該如何修改代碼!!
其實在java動態代理中,就已經解決了這種問題,本人將從以下幾個方面,幫助大家理解動態代理的知識。對于懂java的“安全牛”來說這是一件很簡單的事情,本文目的主要是記錄下解決問題的過程。
-
靜態代理
-
jdk動態代理
-
CGLIB代理
-
Spring AOP
為什么使用動態代理
作為在乙方工作的“安全工程獅”有時候想一下還是幸福的,最近通過跟甲方的某獅子交流,發現業務量很大的情況下,一旦發生了安全問題,解決起來真是個麻煩的事情,需要收集資產,要出方案,最難的是教會開發修補漏洞,仔細思考了這個問題,遂想到了java動態代理,周末的時候研究了一下,現在分享給大家。設想一下,如果你挨個去教給開發應該怎么去修復漏洞,那么24小時之內完成應急是根本不可能完成的。比較高效的方法是,安全的邏輯都由安全部門實現,我們只需要留給開發一個接口供他們去使用就ok。那怎么樣才可能通過,不修改源代碼的情況下,增加業務的安全性,就是通過今天說的java動態代理。
靜態代理
定義接口:
public interface Hello1 {
public void say(String name);
}
實現類:
public class HelloImpl implements Hello1{
@Override
public void say(String name) {
// TODO Auto-generated method stub
System.out.println("Hello"+name);
}
}
hello1代理類: public class HelloProxy implements Hello1{ private Hello1 hello;
public HelloProxy(){
hello=new HelloImpl();
}
@Override
public void say(String name){
before();
hello.say(name);
after();
}
private void after() {
// TODO Auto-generated method stub
System.out.println("after");
}
private void before() {
// TODO Auto-generated method stub
System.out.println("before");
}
}</code></pre>
主函數:
public static void main(String[] args){
Hello1 helloProxy=new HelloProxy();
helloProxy.say("Jack");
}
由上面的過程可以看得出來,我們通過hello1的代理類,增加了say()函數,通過代理,實現了before和after函數。這就是我要說的代理,只不過這事靜態代理,通用性差,修改起來麻煩。下面說動態代理。
jdk動態代理
public class DynamicProxy2 implements InvocationHandler {
public Object target;
@SuppressWarnings("unchecked")
public <T> T getProxy(){
return (T)Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
public DynamicProxy2(Object target) {
// TODO Auto-generated constructor stub
this.target=target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
before();
Object result=method.invoke(target, args);
after();;
return result;
}
private void after() {
// TODO Auto-generated method stub
System.out.println("after");
}
private void before() {
// TODO Auto-generated method stub
System.out.println("before");
}
主函數:
public static void main(String[] args) {
// TODO Auto-generated method stub
DynamicProxy2 dynamicProxy2 = new DynamicProxy2(new HelloImpl());
Hello1 helloproxy= dynamicProxy2.getProxy();
helloproxy.say("hi java");
}
這里可以看到通過jdk動態代理,首先實現InvocationHandler接口,然后實現了invoke方法。從主函數中可以看到,這里我們并不關心你的類是什么,你的接口是什么,只要你把實現接口的類傳遞進來,就可以了,這個方案看起來是很不錯的。好像可以解決一開始的需求,但是jdk動態代理只能代理接口,而不能代理沒有接口的類,這種情況該怎么解決?
CGLIB動態代理
public class CGLibProxy implements MethodInterceptor {
@SuppressWarnings("unchecked")
public<T> T getProxy(Class<T> cls){
return (T) Enhancer.create(cls, this);
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// TODO Auto-generated method stub
before();
Object result=proxy.invokeSuper(obj, args);
after();
return result;
}
private void after() {
// TODO Auto-generated method stub
System.out.println("after");
}
private void before() {
// TODO Auto-generated method stub
System.out.println("before");
}}
主函數:
public static void main(String[] args) {
// TODO Auto-generated method stub
CGLibProxy cglibproxy=new CGLibProxy();
Hello1 helloproxy=cglibproxy.getProxy(HelloImpl.class);
helloproxy.say("asd");
}
這里需要引入開篇時候的那個jar包。CGLIB可以代理沒有接口的類,這就彌補了jdk動態代理的不足。通過jdk,cglib動態代理,就可以解決以上遇到的問題。
來自:http://www.freebuf.com/articles/web/118334.html