>백엔드 개발 >PHP 튜토리얼 >PHP 직렬화 및 역직렬화 원칙에 대한 자세한 설명

PHP 직렬화 및 역직렬화 원칙에 대한 자세한 설명

jacklove
jacklove원래의
2018-06-30 18:01:061799검색

이 문서는 PHP 역직렬화 취약점 시리즈에서 PHP 직렬화 및 역직렬화 원칙에 대한 관련 지식을 공유합니다. 이 문서가 필요한 친구는 이를 참조할 수 있습니다.

0. 서문

객체의 직렬화 및 역직렬화는 자세히 설명하지 않습니다. PHP의 직렬화 결과는 json과 다소 유사한 PHP 사용자 정의 문자열 형식입니다.

모든 언어에서 사용할 수 있습니다. 객체 직렬화 및 역직렬화를 설계할 때 해결해야 할 몇 가지 문제가 있습니다. 객체를 직렬화한 후 직렬화 결과에는 자체 설명 기능이 있습니다(객체의 특정 유형은 직렬화 결과에서 알 수 있으므로


유형을 아는 것만으로는 충분하지 않습니다). , 물론 이 유형에 해당하는 특정 값도 알아야 합니다.


직렬화 중 권한 제어, 직렬화 필드 등을 사용자 정의할 수 있습니다. 예를 들어 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

두 번째 줄을 참조하세요. 출력, 이 문자열은 실제로 직렬화의 결과입니다. 물론, 서로 다른 접근권한을 가진 멤버들을 직렬화한 후의 레이블 이름은 조금씩 다릅니다.

위에서 언급한 세 가지 질문에 따르면, 봐

1. 자기 설명 기능

O:5:"fobnn":2 여기서 o는 객체 유형을 나타내고 유형 이름은 fobnn입니다. 이 형식에서 다음 2는 두 개의 구성원 객체가 있음을 나타냅니다.

멤버 개체에 대해서는 실제로 동일한 하위 설명 집합입니다.

자기 설명의 기능은 주로 문자열을 통해 개체 및 멤버의 이름을 기록하는 것입니다.

2. 성능 문제

이 기사에서는 PHP 직렬화의 시간 성능을 분석하지 않지만, 직렬화 결과는 실제로 json/bson에서 정의한 프로토콜과 유사합니다. 헤더는 유형에 해당하는 값을 설명하며 직렬화 결과를 압축하지 않습니다.

2. 역직렬화의 마법 메서드

실제로도 이 문제에 해당합니다. 해결책은 PHP에 있습니다. 하나는 매직 메소드를 이용하는 것이고, 두 번째는 직렬화 전에 매직 메소드 __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

을 소개하는 것입니다. 이런 식으로 직렬화해야 하는 데이터를 제어할 수 있습니다. 이 경우에는 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 중국어 웹사이트를 지원합니다.

관심을 가질 만한 기사:

Swoole 기반 WeChat QR 코드 로그인 기능의 코드 구현 프로세스에 대한 설명


PHP7 확장 개발의 안녕하세요 단어 구현 방법에 대한 자세한 설명


PHP 확장 기능 개발 함수 기반의 lib 라이브러리 사용법에 대한 자세한 설명


위 내용은 PHP 직렬화 및 역직렬화 원칙에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.