一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - PHP教程 - 詳解PHP序列化和反序列化原理

詳解PHP序列化和反序列化原理

2019-10-25 13:13laozhang PHP教程

本篇文章給大家分享了下PHP反序列化漏洞系列之PHP序列化和反序列化原理的相關知識,有這方面需要的朋友參考學習下吧。

0.前言

對象的序列化和反序列化作用就不再贅述,php中序列化的結果是一個php自定義的字符串格式,有點類似json.

我們在任何語言中設計對象的序列化和反序列化都需要解決幾個問題

把某個對象序列化之后,序列化的結果有自描述的功能(從序列化的結果中知道這個對象的具體類型,

知道類型還不夠,當然還需要知道這個類型所對應具體的值).

序列化時的權限控制,可以自定義序列化字段等,例如golang中的做的就非常方便.

時間性能問題:在某些性能敏感的場景下,對象序列化就不能拖后腿,例如:高性能服務(我經常使用protobuf來序列化).

空間性能問題:序列化之后的結果不能太長,比如內存中一個int對象,序列化之后數據長度變成了10倍int的長度,那這個序列化算法是有問題的.

本文僅僅從php代碼角度來解釋php中序列化和反序列化的過程.,記住一點序列化和反序列化操作的僅僅是對象的數據,這一點有面向對象開發經驗的都應該容易理解.

1.序列化serialize和反序列化方法unserialize

php原生提供了對象序列化功能,不像c++ ……^_^. 用起來也非常簡單,就兩個接口.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class fobnn
{
 public $hack_id;
 private $hack_name;
 public function __construct($name,$id)
 {
  $this->hack_name = $name;
  $this->hack_id = $id;
 }
 public function print()
 {
  echo $this->hack_name.PHP_EOL;
 }
}
$obj = new fobnn('fobnn',1);
$obj->print();
$serializedstr = serialize($obj); //通過serialize接口序列化
echo $serializedstr.PHP_EOL;;
$toobj = unserialize($serializedstr);//通過unserialize反序列化
$toobj->print();
?
1
2
3
fobnn
O:5:"fobnn":2:{s:7:"hack_id";i:1;s:16:"fobnnhack_name";s:5:"fobnn";}
fobnn

看到第二行的輸出,這個字符串就是序列化的結果,這個結構其實很容讀懂,可以發現是通過對象名稱/成員名稱來映射的,當然不同訪問權限的成員序列化之后的標簽名稱略有不同.

根據我上面講到的3個問題,那么我們可以來看看

1.自描述功能

O:5:"fobnn":2 其中o就表示了object類型,且類型名稱為fobnn, 采用這種格式,后面的2表示了有2個成員對象.

關于成員對象,其實也是同一套子描述,這是一個遞歸的定義.

自描述的功能主要是通過字符串記錄對象和成員的名稱來實現.

2.性能問題

php序列化的時間性能本文就不分析了,詳見后面,但序列化結果其實類似json/bson定義的協議,有協議頭,協議頭說明了類型,協議體則說明了類型所對應的值,并不會對序列化結果進行壓縮.

2.反序列化中的魔術方法

對應上述說的第二個問題,其實php中也有解決方法,一種是通過魔術方法,第二種則是自定義序列化函數.先來介紹下魔術方法 __sleep和__wakeup

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class fobnn
{
 public $hack_id;
 private $hack_name;
 public function __construct($name,$id)
 {
  $this->hack_name = $name;
  $this->hack_id = $id;
 }
 public function print()
 {
  echo $this->hack_name.PHP_EOL;
 }
 public function __sleep()
 {
  return array("hack_name");
 }
 public function __wakeup()
 {
  $this->hack_name = 'haha';
 }
}
$obj = new fobnn('fobnn',1);
$obj->print();
$serializedstr = serialize($obj);
echo $serializedstr.PHP_EOL;;
$toobj = unserialize($serializedstr);
$toobj->print();
?
1
2
3
fobnn
O:5:"fobnn":1:{s:16:"fobnnhack_name";s:5:"fobnn";}
haha

在序列化之前會先調用__sleep返回的是一個需要序列化的成員名稱數組,通過這樣我們就可以控制需要序列化的數據,案例中我只返回了hack_name,可以看到結果中只序列化了hack_name成員.

在序列化完成之后,會跳用__wakeup 在這里我們可以做一些后續工作,例如重連數據庫之類的.

3.自定義Serializable接口

?
1
2
3
4
interface Serializable {
abstract public string serialize ( void )
abstract public void unserialize ( string $serialized )
}

通過這個接口我們可以自定義序列化和反序列化的行為,這個功能主要可以用來自定義我們的序列化格式.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class fobnn implements Serializable
{
 public $hack_id;
 private $hack_name;
 public function __construct($name,$id)
 {
  $this->hack_name = $name;
  $this->hack_id = $id;
 }
 public function print()
 {
  echo $this->hack_name.PHP_EOL;
 }
 
 public function __sleep()
 {
  return array('hack_name');
 }
 
 public function __wakeup()
 {
  $this->hack_name = 'haha';
 }
 
 public function serialize()
 {
  return json_encode(array('id' => $this->hack_id ,'name'=>$this->hack_name ));
 }
 
 public function unserialize($var)
 {
  $array = json_decode($var,true);
  $this->hack_name = $array['name'];
  $this->hack_id = $array['id'];
 }
}
$obj = new fobnn('fobnn',1);
$obj->print();
$serializedstr = serialize($obj);
echo $serializedstr.PHP_EOL;;
$toobj = unserialize($serializedstr);
$toobj->print();
?
1
2
3
fobnn
C:5:"fobnn":23:{{"id":1,"name":"fobnn"}}
fobnn

當使用了自定義序列化接口之后,我們的魔術方法就沒用了.

4.PHP動態類型和PHP反序列化

既然上文中提到的自描述功能,那么序列化結果中保存了對象的類型,且php是動態類型語言,那么我們就可以來做個簡單的實驗.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class fobnn
{
 public $hack_id;
 public $hack_name;
 public function __construct($name,$id)
 {
  $this->hack_name = $name;
  $this->hack_id = $id;
 }
 public function print()
 {
  var_dump($this->hack_name);
 }
}
$obj = new fobnn('fobnn',1);
$obj->print();
$serializedstr = serialize($obj);
echo $serializedstr.PHP_EOL;;
$toobj = unserialize($serializedstr);
$toobj->print();
$toobj2 = unserialize("O:5:"fobnn":2:{s:7:"hack_id";i:1;s:9:"hack_name";i:12345;}");
$toobj2->print();

我們修改hack_name反序列化的結果為int類型, i:12345

?
1
2
3
4
string(5) "fobnn"
O:5:"fobnn":2:{s:7:"hack_id";i:1;s:9:"hack_name";s:5:"fobnn";}
string(5) "fobnn"
int(12345)

可以發現,對象成功序列化回來了!并且可以正常工作!. 當然php的這種機制提供了靈活多變的語法,但也引入了安全風險. 后續繼續分析php序列化和反序列化特性帶來的安全問題.

以上就是我們整理的關于PHP序列化和反序列化原理的全部知識內容,感謝你對服務器之家的支持。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 国产色视频一区二区三区 | 国产高清在线精品一区二区三区 | 啪啪链接| 亚洲视频免费在线看 | 色综合天天娱乐综合网 | 国产精品一级片 | 第一次做m被调教经历 | 国产一级视频在线观看 | 午夜爽喷水无码成人18禁三级 | 国产精品久久久久久久久 | 成人丁香乱小说 | les女同h高h喷水 | 欧美国产在线 | 91亚洲一区二区在线观看不卡 | 天天拍天天色 | 青山葵在线 | 国产成人咱精品视频免费网站 | 国产美女下面流出白浆视频 | katsuniav在线播放 | 亚洲国产区男人本色在线观看欧美 | 日韩美女强理论片 | 爽好舒服快想要免费看 | 美女全身体光羞羞漫画 | 国产成人看片免费视频观看 | 日本一区二区三区视频在线观看 | 久久婷婷五月综合色精品首页 | 紧身裙女教师波多野结衣 | 欧美亚洲国产另类在线观看 | 石原莉奈adn093店长未婚妻 | 放荡护士玩3p口述 | 特黄a大片免费视频 | 扒开双腿猛进入爽爽视频ai | haodiaocao几万部精彩视频 | 亲爱的客栈第二季免费观看完整版 | 日本mature乱子视频 | 99热精品国产麻豆 | 国产成人精品日本亚洲网址 | 色8| ysl千人千色t9t9t9 | 女同69式互添在线观看免费 | 午夜大片在线观看 |