1. 程式人生 > >javaweb-codereview 學習記錄-5

javaweb-codereview 學習記錄-5

1.關於URLConnection

 應用程式利用url與遠端通訊的所有類的超類

jdk1.8中支援的協議包括以上這些,gopher在jdk8中取消了。

java中預設對(http|https)做了一些事情,比如:

預設啟用了透明NTLM認證
預設跟隨跳轉

httpURLconnection可能jdk7低版本可能在win機器上導致ntlmrelay攻擊https://zhuanlan.zhihu.com/p/64889695

使用URLconnection的子類可能只適合http|https,對ssrf也有一定的限制

HttpURLConnection
HttpClient
Request
okhttp

2.關於java agent

Java中Instrumentation(Java Agent API)JVMTI(JVM Tool Interface)功能,允許JVM在載入某個class檔案之前對其位元組碼進行修改,同時也支援對已載入的class(類位元組碼)進行重新載入(Retransform),rsap和iast都基於這個功能實現動態修改java位元組碼來插入檢測程式碼

java agent的兩種執行模式:

1.直接在命令新增執行引數 -javaagent(Instrumentation API實現方式)或-agentpath/  -agentlib(JVMTI的實現方式)

2.attach方式,直接將agent加到對應的java程序

helloWorld.java

public class helloWorld {
    public static void main(String[] args){
        System.out.println("hello world");
    }
}

比如就上面一段簡單的程式碼,編譯後取修改器位元組碼讓其輸出hello world,想一下hello world在編譯後儲存在class檔案中,那麼此時已經編譯成位元組碼,要輸出的字串肯定也是以位元組碼儲存著,那麼此時可以直接替換獲取編譯好的位元組碼進行修改

testagent.java

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
import java.util.Arrays;

public class testagent {

    private static byte[] relaceBytes(String classname,byte[] classbuffer)
    {
        String bufferStr = Arrays.toString(classbuffer).replace("[","").replace("]","");
        System.out.println("classname:"+classname);
        System.out.println("byes:"+ bufferStr);

        byte[] findBytes = "hello world".getBytes();
        String findStr = Arrays.toString(findBytes).replace("[","").replace("]","");
        System.out.println("world"+findStr);
        byte[] replaceBytes = "hello agent".getBytes();
        String replaceStr = Arrays.toString(replaceBytes).replace("[","").replace("]","");
        System.out.println("agent"+replaceStr);
        bufferStr = bufferStr.replace(findStr,replaceStr);

        System.out.println(bufferStr);

        String[]  bytearr = bufferStr.split("\\s*,\\s*");

        byte[] bytes = new byte[bytearr.length];

        for(int i=0;i < bytearr.length;i++)
        {
            bytes[i] = Byte.parseByte((bytearr[i]));

        }

        System.out.println("new byte :"+Arrays.toString(bytes));

        return bytes;




    }
    public static void premain(String args,final Instrumentation inst){
        inst.addTransformer(new ClassFileTransformer() {
            public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {

            className = className.replace("/",".");
               if(className.equals("helloWorld")){
                 return   relaceBytes(className,classfileBuffer);

               }
                return classfileBuffer;
            }
        },true);

    }
}

這裡的classfileBuffer就是要修改位元組碼的class檔案,這裡替換位元組的函式可以自定義,只要返回一個位元組陣列即可

  測試的時候testagent.java編譯後要包含MANIFEST.MF,宣告premain-class

  然後使用jar命令打包

jar -cvfm agent.jar MANIFEST.MF *.class

之後再到helloWorld.class的目錄執行agent即可

java -javaagent:agent.jar helloWorld

 這裡一般修改位元組碼用ASM庫

Instrumentation

java提供的監測jvm程式的api,利用Instrumentation我們可以實現

1.動態新增Transformer(addTransformer),上面的例子就是

2.動態修改classpath(appendToBootstrapClassLoaderSearch、appendToSystemClassLoaderSearch)

3.動態獲取所有JVM已經載入的類(getAllLoadedClasses)

4.動態獲取某個類載入器已經例項化的所有類(getInitiatedClasses)

5.直接修改已載入的類的位元組碼

6.動態設定JNI字首(setNativeMethodPrefix)

7.重載入指定類位元組碼(retransformClasses)

ClassFileTransformer

轉換類檔案的代理介面,拿到Instrumentation後可以呼叫addTransformer方法新增自定義的類檔案轉換器,上面的例子實際上就自定義了

一個Transformer,此時transform(類名,類載入器,類位元組碼等)方法就包含了我們要修改的目標類的一些資訊,修改完再返回位元組碼,jvm對位元組碼進行驗證後將決定是否載入。

這裡簡單記錄一下,後面有機會再深入學習。

&n