溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Java序列化和反序列化出現(xiàn)漏洞的解決方案

發(fā)布時間:2020-08-05 17:12:58 來源:億速云 閱讀:214 作者:小新 欄目:開發(fā)技術(shù)

這篇文章將為大家詳細(xì)講解有關(guān)Java序列化和反序列化出現(xiàn)漏洞的解決方案,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

Java序列化

Java 提供了一種對象序列化的機制,該機制中,一個對象可以被表示為一個字節(jié)序列,該字節(jié)序列包括該對象的數(shù)據(jù)、有關(guān)對象的類型的信息和存儲在對象中數(shù)據(jù)的類型。

Java反序列化

反序列化就是將字節(jié)序列恢復(fù)為Java對象的過程

整個過程都是 Java 虛擬機(JVM)獨立的,也就是說,在一個平臺上序列化的對象可以在另一個完全不同的平臺上反序列化該對象,因此可以實現(xiàn)多平臺之間的通信、對象持久化存儲,主要有如下幾個應(yīng)用場景。

HTTP:多平臺之間的通信,管理等

RMI:是 Java 的一組擁護(hù)開發(fā)分布式應(yīng)用程序的 API,實現(xiàn)了不同操作系統(tǒng)之間程序的方法調(diào)用。值得注意的是,RMI 的傳輸 100% 基于反序列化,Java RMI 的默認(rèn)端口是1099端口。

JMX:JMX 是一套標(biāo)準(zhǔn)的代理和服務(wù),用戶可以在任何 Java 應(yīng)用程序中使用這些代理和服務(wù)實現(xiàn)管理,中間件軟件 WebLogic 的管理頁面就是基于 JMX 開發(fā)的,而 JBoss 則整個系統(tǒng)都基于 JMX 構(gòu)架。

系列化反序列化基礎(chǔ)

序列化和反序列化本身并不存在問題。但當(dāng)輸入的反序列化的數(shù)據(jù)可被用戶控制,那么攻擊者即可通過構(gòu)造惡意輸入,讓反序列化產(chǎn)生非預(yù)期的對象,在此過程中執(zhí)行構(gòu)造的任意代碼。

一個類的對象能夠序列化的成功需要兩個條件

  • 該類必須實現(xiàn) java.io.Serializable 接口
  • 該類的所有屬性必須是可序列化的。如果有一個屬性不是可序列化的,則該屬性必須注明是短暫的。

漏洞基本原理

簡單的反序列化Demo

首先定義對象類Persion,包含兩個參數(shù)

public class implements java.io.Serializable{
  public String name;
  public int age;
  public void info(){
    System.out.println("Name:"+this.name+";nAge:"+this.age);
  }
}

在主類中聲明對象,并且將對象序列化為二進(jìn)制文件,將其存儲到硬盤中

import java.io.*;

public class Main{
  public static void main(String [] args){
    將對象序列化為二進(jìn)制文件
    Persion p = new Persion();
    p.name = "Joner";
    p.age = 18;
    try {

      //打開一個文件輸入流
      FileOutputStream fileOut = new FileOutputStream("D:\test\test.db");
      //建立對象輸入流
      ObjectOutputStream out = new ObjectOutputStream(fileOut);
      //輸出反序列化對象
      out.writeObject(p);
      out.close();
      fileOut.close();
      System.out.printf("保存成功");
    }catch(IOException i){
      i.printStackTrace();
    }
}

進(jìn)行反序列化

import java.io.*;

public class Main{
  public static void main(String [] args){
    /*從二進(jìn)制文件中提取對象*/
    Persion persion = null;
    try{
      FileInputStream fileInputStream = new FileInputStream("D:\test\test.db");
      //建立對象輸入流
      ObjectInputStream inputStream = new ObjectInputStream(fileInputStream);
      persion = (Persion) inputStream.readObject();
      inputStream.close();
      fileInputStream.close();
    }catch (ClassNotFoundException c){
      System.out.println("對象未找到");
      c.printStackTrace();
      return;
    } catch (FileNotFoundException e) {
      e.printStackTrace();
      return;
    } catch (IOException e) {
      e.printStackTrace();
      return;
    }
    System.out.println("反序列化對象.......");
    System.out.println("Name:"+persion.name);
    System.out.println("Age:"+persion.age);
    }
}

查看test.db文件的內(nèi)容可以看見如下內(nèi)容

其中 AC ED 00 05 是java 序列化內(nèi)容的特征,其中00 05 是版本信息,base64編碼后為ro0AB

反序列化漏洞Demo

在上面的Demo中可以看到,進(jìn)行反序列化時會調(diào)用readObject()方法,如果readObject方法書寫不當(dāng)就會引發(fā)漏洞。

import java.io.*;

public class Main{
  public static void main(String [] args)throws Exception{
    Unsafeclass unsafeclass = new Unsafeclass();
    unsafeclass.name = "hhhhh";
    FileOutputStream fileOutputStream = new FileOutputStream("object");
    ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
    //將對象寫入object文件
    objectOutputStream.writeObject(unsafeclass);
    objectOutputStream.close();

    //從文件中反序列化對象
    FileInputStream fileInputStream = new FileInputStream("object");
    ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
    //恢復(fù)對象
    Unsafeclass objectFormDisk = (Unsafeclass)objectInputStream.readObject();
    System.out.println(objectFormDisk.name);
    objectOutputStream.close();
  }
}
class Unsafeclass implements Serializable{
  public String name;
  //重寫readObject()方法
  private void readObject(java.io.ObjectInputStream inputStream ) throws IOException , ClassNotFoundException{
    //執(zhí)行默認(rèn)的readObdect()方法
    inputStream.defaultReadObject();
    //執(zhí)行打開計算器命令
    Runtime.getRuntime().exec("calc.exe");
  }
}

程序運行過程為:

  • UnsafeClass類背序列化進(jìn)入object文件
  • 從object文件中恢復(fù)對象
  • 調(diào)用被恢復(fù)對象的readObject()方法
  • 命令被執(zhí)行

這樣看感覺并不會有人會這樣寫readobject()這個方法,而且一些成熟的框架都會有防范反序列化的方法,但仍有很大比例的反序列化漏洞,這主要是使用了不安全的庫造成的。上面只是介紹了簡單的Java反序列化過程,接下來會有一篇文章介紹反序列化漏洞檢測方法以及復(fù)現(xiàn)一些經(jīng)典反序列化漏洞。

關(guān)于Java序列化和反序列化出現(xiàn)漏洞的解決方案就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI