PHP のシリアル化と逆シリアル化の原理の詳細な説明

jacklove
リリース: 2023-04-02 07:58:01
オリジナル
1768 人が閲覧しました

この記事では、PHP デシリアライゼーションの脆弱性シリーズで、PHP のシリアル化とデシリアライゼーションの原則に関する関連知識を共有します。これが必要な友人は参照してください。

0. はじめに

オブジェクトのシリアル化および逆シリアル化関数については、詳細には説明しません。PHP でのシリアル化の結果は、PHP でカスタマイズされた文字列形式になります。 json に似ています。

任意の言語でオブジェクトのシリアル化と逆シリアル化を設計するときは、いくつかの問題を解決する必要があります。

オブジェクトをシリアル化した後、シリアル化の結果は自己記述関数 (シリアル化の結果からこのオブジェクトの特定の型を取得します。

#型を知るだけでは十分ではありません。もちろん、この型に対応する特定の値も知る必要があります)。

シリアル化中の権限制御、シリアル化フィールドなどをカスタマイズできます。たとえば、golang で行うと非常に便利です。

時間パフォーマンスの問題: 一部のパフォーマンス重視のシナリオでは、オブジェクトのシリアル化例: 高パフォーマンスのサービス (シリアル化に protobuf をよく使用します)

スペースのパフォーマンスの問題: シリアル化後の結果が長すぎてはなりません (メモリ内の int など) オブジェクト, シリアル化後、データ長が int の長さの 10 倍になる場合、このシリアル化アルゴリズムには問題があります。

この記事では、PHP コードの観点から PHP のシリアル化と逆シリアル化についてのみ説明します。

#1. シリアル化と逆シリアル化のメソッド unserialize

php は、c...^_^ とは異なり、オブジェクトのシリアル化機能をネイティブに提供します。また、使い方も非常に簡単で、インターフェイスが 2 つだけです。

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. 自己記述関数

#O:5:"fobnn":2 ここで、o はオブジェクト タイプを表し、タイプ名は fobnn です。この形式を使用すると、次の内容が続きます。 2 は、2 つのメンバー オブジェクトがあることを示します.

メンバー オブジェクトに関しては、実際には同じサブ記述のセットです。これは再帰的定義です。

自己記述の機能は、主に文字列と

#2. パフォーマンスの問題

PHP シリアル化の時間パフォーマンスはこの記事では分析されません。詳細は後述しますが、シリアル化の結果は実際には次のとおりです。 json/bson で定義 プロトコルにはプロトコルヘッダーがあり、プロトコルヘッダーには型が記述され、プロトコルボディには型に応じた値が記述されます。シリアル化結果は圧縮されません。逆シリアル化メソッドのマジック

は、上で説明した 2 番目の問題に対応します。実際、PHP にも解決策があります。1 つはマジック メソッド、もう 1 つはカスタム シリアル化関数によるものです。マジック メソッド __sleep と __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
ログイン後にコピー

は、シリアル化する前に最初に __sleep を呼び出して戻ります。はシリアル化する必要があるメンバー名の配列です。これにより、シリアル化する必要があるデータを制御できます。この場合は、hack_name のみを返しました。結果では、hack_name メンバーのみがシリアル化されていることがわかります。

「シリアル化が完了した後、__wakeup が使用されます。ここで、データベースへの再接続などのフォローアップ作業を行うことができます。

#3. シリアル化可能なインターフェイスのカスタマイズ

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 のシリアル化および逆シリアル化機能によって引き起こされるセキュリティ問題を分析するために使用します。

上記は、PHP のシリアル化および逆シリアル化の原則についてまとめたすべての知識です。PHP 中国語 Web サイトのサポートについてご理解いただき、ありがとうございます。

興味があるかもしれない記事:

Swoole に基づく WeChat コード スキャン ログイン機能のコード実装プロセスの説明

PHP7拡張開発におけるhello wordの実装方法の詳細説明


PHPの関数メソッドによるlibライブラリの利用方法の詳細説明拡張機能の開発


以上がPHP のシリアル化と逆シリアル化の原理の詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート