0.前言
本文為篤行日常學習記錄,web安全php漏洞系列。
對象的序列化和反序列化作用就不再贅述,php中序列化的結果是一個php自定義的字符串格式,有點類似json.
我們在任何語言中設計對象的序列化和反序列化都需要解決幾個問題
把某個對象序列化之后,序列化的結果有自描述的功能(從序列化的結果中知道這個對象的具體類型,
知道類型還不夠,當然還需要知道這個類型所對應具體的值).
序列化時的權限控制,可以自定義序列化字段等,例如golang中的做的就非常方便.
時間性能問題:在某些性能敏感的場景下,對象序列化就不能拖后腿,例如:高性能服務(我經常使用protobuf來序列化).
空間性能問題:序列化之后的結果不能太長,比如內存中一個int對象,序列化之后數據長度變成了10倍int的長度,那這個序列化算法是有問題的.
本文僅僅從php代碼角度來解釋php中序列化和反序列化的過程.,記住一點序列化和反序列化操作的僅僅是對象的數據,這一點有面向對象開發經驗的都應該容易理解.
1.序列化serialize和反序列化方法unserializephp原生提供了對象序列化功能,不像c++ ……^_^. 用起來也非常簡單,就兩個接口.
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();
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
http://php.net/manual/en/lang...
http://php.net/manual/en/lang...
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();
fobnn O:5:"fobnn":1:{s:16:"fobnnhack_name";s:5:"fobnn";} haha
在序列化之前會先調用__sleep返回的是一個需要序列化的成員名稱數組,通過這樣我們就可以控制需要序列化的數據,案例中我只返回了hack_name,可以看到結果中只序列化了hack_name成員.
在序列化完成之后,會跳用__wakeup 在這里我們可以做一些后續工作,例如重連數據庫之類的.
3.自定義Serializable接口自定義序列化接口 http://php.net/manual/en/clas...
interface Serializable { abstract public string serialize ( void ) abstract public void unserialize ( string $serialized ) }
通過這個接口我們可以自定義序列化和反序列化的行為,這個功能主要可以用來自定義我們的序列化格式.
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();
fobnn C:5:"fobnn":23:{{"id":1,"name":"fobnn"}} fobnn
當使用了自定義序列化接口之后,我們的魔術方法就沒用了.
4.PHP動態類型和PHP反序列化既然上文中提到的自描述功能,那么序列化結果中保存了對象的類型,且php是動態類型語言,那么我們就可以來做個簡單的實驗.
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
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序列化和反序列化特性帶來的安全問題.
最后 ending…如有不足請指點,亦可留言或聯系 fobcrackgp@163.com.
本文為篤行原創文章首發于大題小作,永久鏈接:PHP反序列化漏洞系列之--PHP序列化和反序列化原理
https://www.ifobnn.com/phpserialize.html
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/26328.html
摘要:和函數這兩個是序列化和反序列化中數據的常用函數。序列化數組輸出結果反序列化輸出結果當數組值包含如雙引號單引號或冒號等字符時,它們被反序列化后,可能會出現問題。序列化反序列化但是編碼將增加字符串的長度。序列化數組輸出結果反序列化 序列化是將變量轉換為可保存或傳輸的字符串的過程;反序列化就是在適當的時候把這個字符串再轉化成原來的變量使用。這兩個過程結合起來,可以輕松地存儲和傳輸數據,使程序...
摘要:查閱官方文檔后得知,新版為了防止對象的序列化反序列化漏洞被利用,不再對值進行自動的序列化和反序列化處理。舉個栗子更新到后,因為不再自動對值進行序列化處理,而只能加密字符串數據,這個時候程序就會拋出錯誤。 最近手殘升級了項目里 Laravel 的小版本號(v5.5.39 => v5.5.45),這不升級則已,一升級就出了問題! Sentry 平臺上提示錯誤:openssl_encrypt...
摘要:實現里的安裝用法世界上最好的語言世界上最好的語言世界上最好的語言地址 Golang 實現 PHP里的 serialize() 、 unserialize() 安裝 go get -u github.com/techoner/gophp 用法 package main import ( fmt github.com/techoner/gophp/serialize )...
摘要:背后性能影響還是挺大的。缺失的異常剛開始寫代碼的時候一直不明白為什么要用異常,感覺就能搞定了,為什么還要多此一舉,現在反而覺得的異常太少。在的時候,如果出現異常,可以通過來獲取。 作為一名深度 phper,我如果要黑咱們 php,就像說自己母校差一樣,大家不要見外。個人博客地址:https://mengkang.net/1368.html 故事的開始 這幾天觀察錯誤日志發現有一個數據...
閱讀 2993·2021-10-13 09:39
閱讀 2694·2021-09-27 13:34
閱讀 2031·2019-08-30 15:55
閱讀 3260·2019-08-30 15:43
閱讀 3631·2019-08-30 11:16
閱讀 1748·2019-08-26 18:28
閱讀 1284·2019-08-26 13:56
閱讀 915·2019-08-26 13:35