この記事では、主に PHP デシリアライゼーションの脆弱性シリーズの PHP シリアル化とデシリアライゼーションの原理に関する関連知識を共有します。必要な方は参照してください。皆さんのお役に立てれば幸いです。
前書き
PHP でのオブジェクトのシリアル化と逆シリアル化の結果は、JSON に似た PHP カスタマイズされた文字列形式になります。
私たちは任意の言語で設計します。オブジェクトの逆シリアル化には、いくつかの問題を解決する必要があります
オブジェクトをシリアル化した後、シリアル化の結果には自己記述関数が含まれます (オブジェクトの特定の型はシリアル化の結果からわかります。
もちろん、型を知るだけでは十分ではありません)このタイプに対応する特定の値も知っておく必要があります)。
シリアル化中の権限制御、シリアル化フィールドなどをカスタマイズできます。たとえば、golang で行うと非常に便利です。問題点: 一部のパフォーマンス重視のシナリオでは、オブジェクトのシリアル化が障害になることはありません。高パフォーマンスのサービス (私はシリアル化に protobuf をよく使用します)
スペースのパフォーマンスの問題: たとえば、シリアル化後の結果が長すぎることはできません。 , メモリ内の int オブジェクトがシリアル化され、データ長が int の長さの 10 倍になる場合は、シリアル化アルゴリズムに問題があります
この記事では、php コードの観点から php のシリアル化と逆シリアル化についてのみ説明します。シリアル化と逆シリアル化はオブジェクト データに対してのみ動作することを覚えておいてください。オブジェクト指向開発の経験がある人なら誰でも、これを簡単に理解できるはずです。 unserialize
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
出力の 2 行目を参照してください。この文字列はシリアル化の結果です。この構造は実際には簡単です。もちろん、異なるアクセス権を持つメンバーのシリアル化後のラベル名は少し異なります。上記の 3 つの質問によると、次のことがわかります。見てください
1. 自己記述関数
メンバー オブジェクトに関しては、実際には同じサブ記述のセットです。
自己記述関数は、主に文字列を通じてオブジェクトとメンバーの名前を記録することによって実装されます。パフォーマンスの問題
PHP シリアル化の時間パフォーマンスはこの記事では分析されません。詳細は後ほど参照しますが、シリアル化の結果は実際には json/bson で定義されたプロトコルに似ています。プロトコル ヘッダーには、プロトコル ヘッダーが記述されています。型に対応する値がシリアル化結果を圧縮しないことを説明しています
2. 実際には、上記の 2 番目の問題に対応します。これも PHP での解決策です。1 つはマジック メソッドを使用するもので、2 つ目はカスタム シリアル化関数を使用するものです。まず、シリアル化する前に __sleep と __wakeup を導入します。最初に __sleep が呼び出されます。 return シリアル化する必要があるメンバー名の配列です。この場合、hack_name メンバーのみがシリアル化されていることがわかります。 シリアル化が完了すると、データベースへの再接続などのフォローアップ作業を行うことができる __wakeup にジャンプします。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
interface Serializable { abstract public string serialize ( void ) abstract public void unserialize ( string $serialized ) }
カスタムシリアル化インターフェイスが使用されている場合、マジックメソッドは役に立ちません。
4 .PHP 動的型とPHPの逆シリアル化
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();
hack_name の逆シリアル化結果を int 型、i:12345 に変更しました
fobnn C:5:"fobnn":23:{{"id":1,"name":"fobnn"}} fobnn
PHPセッションデシリアライゼーションの脆弱性の詳細説明
以上がPHP のシリアル化と逆シリアル化の原理の詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。