PHP - Serialize & Unserialize

PHP에서 SerializeUnserialize에 대해서 정리하고자 한다.

1) 직렬화(Serialize)란 메모리의 값(배열·객체 등)을 저장·전송 가능한 문자열로 변환하는 과정이다.
2) 역직렬화(Unserialize)는 직렬화된 문자열을 다시 PHP 값으로 복원하는 과정이다.

PHP serialize는 복잡한 데이터 구조(배열, 객체 등)를 문자열(바이트 스트림)로 변환할 때 사용하며, 이를 데이터베이스에 저장하거나 세션, 파일 간에 전송할 때 유용하게 활용된다. 변환된 문자열은 unserialize 함수를 통해 다시 원본 데이터 구조로 복원할 수 있다. 주요 활용처는 세션 저장, 캐시, 큐/IPC, 임시 스냅샷 등이다.

기본 문법

$serialized = serialize($value); // 값 -> 문자열
$valueBack = unserialize($serialized); // 문자열 -> 값

타입별 포맷 요약

  • NULL : N;
  • bool : b:0; 또는 b:1;
  • int : i:<정수>;
  • float : d:<부동소수>;
  • string : s:<바이트길이>:"<내용>";
    • 길이는 "문자 개수"가 아니라 "바이트 수". (멀티바이트 고려 필요)
  • array : a:<개수>:{<키><값>...} 이다.
    • 키는 i:<정수>; 또는 s:<길이>:"<문자열>";
    • 삽입 순서 보존
  • object : 0:<클래스명길이>:"<클래스명>":<프로퍼티개수>:{<키><값>...}
    • public 키 : s:<len>:"prop";
    • protected 키 : s:<len>:"\0*\0prop";
    • private 키 : s:<len>:"\0Class\0prop";

예제

$val = [
    'n' => null,        // N;
    'b' => true,        // b:1;
    'i' => 42,          // i:42;
    'd' => 3.14,        // d:3.14;
    's' => "abc",       // s:3:"abc";
    'a' => [1, 2, 3],   // a:3:{i:0,i:1,i:1,i:2,i:2,i:3;}
];

$str = serialize($val);
$back = unserialize($str);

객체 직렬화 커스터마이즈

  • PHP 7.4+에서 __serialize() / __unserialize() 사용이 권장된다.
  • 레거시 __sleep() / __wakeup() 을 사용한다(보안상 주의가 필요하다).
class User {
  private string $name;
  private int $age;

  public function __construct(string $name, int $age) {
    $this->name = $name;
    $this->age  = $age;
  }

  public function __serialize(): array {
    return ['n' => $this->name, 'a' => $this->age];
  }

  public function __unserialize(array $data): void {
    $this->name = $data['n'];
    $this->age  = $data['a'];
  }
}

$u  = new User("Alice", 30);
$s  = serialize($u);
$u2 = unserialize($s);

주의사항

  • 외부 입력을 unserialize()에 넘기면 임의 객체 생성(객체 주입), __wakeup() / __destruct() 실행 등 가젯 체인을 통한 공격이 가능하므로 매우 위험하다.
  • 원칙적으로 신뢰할 수 없는 데이터에 unserialize()를 사용하지 않아야 한다.
  • 불가피할 때는 허용 클래스 화이트리스트를 강제해야 한다.
// 모든 객체 생성을 차단
$val = unserialize($str, ['allowed_classes' => false]);

// 필요한 클래스만 허용
$val = unserialize($str, ['allowed_classes' => ['SafeDTO']]);
  • 가능한 경우 JSON(json_encode / json_decode) 사용이 더 안전하다.

vs JSON?

  • PHP serialize와 json은 데이터를 문자열로 변환하는 데 사용되지만, serialize는 PHP에만 특화되어 객체 등 PHP 타입의 정보를 그대로 유지한다.
  • json은 언어에 구애받지 않고 범용적으로 사용된다. 따라서 PHP에서 내부적으로 사용하기에는 serialize가 더 효율적일 수 있고, 웹 서비스 등 여러 언어와의 호환이 필요할 때는 json이 더 적합하다.

Refer

'Hacker > WEB' 카테고리의 다른 글

퇴근 후 위협 분석&정리 -5  (0) 2025.06.09
퇴근 후 위협 분석&정리 -4  (0) 2025.05.26
퇴근 후 위협 분석&정리 - 3  (0) 2025.05.02
퇴근 후 위협 분석&정리 - 1  (0) 2025.04.28
제 30회 HackingCamp Review & CTF Web Writeup  (0) 2025.02.28