PHP序列化入门
This_is_Y Lv6

来自之前cnblog的博客
源地址:https://www.cnblogs.com/This-is-Y/p/12469046.html

通过序列化与反序列化我们可以很方便的在PHP中进行对象的传递。本质上反序列化是没有危害的。但是如果用户对数据可控那就可以利用反序列化构造payload攻击。

php序列化的作用:

上面的话翻译的直白一点就是方便存储和运输以及传递,举个例子就是:如果想把一个数组或者是对象存储到文件或数据库中,怎么办。不能像字符串那样的存储吧。所以在存储数组或对象之前先对数据进行serialize,在取回内容时再unserialize

也许有人回想,json不也一样吗,我也这样想过,所以去找了一下json和序列化的查别以及优缺点

这里我只把优缺点结果贴出来,详细对比过程可以去这个帖子里看:https://blog.51cto.com/zhweizhi/1952116

 
| |json|serialize
|优点|- 变量序列化后依然可读- 可以给其他系统使用,因为JSON格式是标准的|- 允许非UTF-8的变量- 支持除了stdClass 示例外的其他实例

  • 允许非UTF-8的变量
  • 支持除了stdClass 示例外的其他实例
  • |缺点|- 只对UFT-8的数据有效,其他编码可能不能很好工作- 只对stdClass类的示例有效|- 编码后的文本对人来说是不可读的- 无法被其他语言的系统引用
  • 编码后的文本对人来说是不可读的
  • 无法被其他语言的系统引用
  •  

     

     

     

     

     

     

    同时在那篇文章最后可以看到:

    “我们发现,json序列化和反序列化丢失了类中的私有成员变量,而serialize序列化和反序列化只要是类的变量都可以,但是类的成员方法都无法进行序列化和反序列化。

    在一般情况,还是使用json比较好,因为json是跨平台的通用格式,除了json,用xml也比较好。那在什么时候使用serialize方式呢?

    在对一个类进行****serialize反序列化的时候会默认调用魔术方法__wakeUp(),这样就使得对象能够重新建立起序列化时未能保留的各种状态。例如:数据库连接等。那就是另外一个问题了,这里不做深究了。”

    再重新说回serialize序列化

    serialize()    //将一个对象转化成一个字符串

    unserialize()   //将一个字符串转化成一个对象

    解释一下怎么看serialize的结果

    O:4:”test”表示object名字有四个字符串

    :3表示对象属性有点两个(flag,a)

    {}里的是属性的值

    •   s:10:”testflag”表示string类型,长度为10,值为”testflag”
    •   i:1234表示int类型,值为1234

    这里有个细节要注意,flag只有4,testflag也只有8,但是这里显示的长度却是10。这是因为它是private属性,翻阅文档就可以看到说明,它会在两侧加入空字节。所以在传入序列化字符串进行反序列化时需要注意补齐两个空字节。

    再扯一下public、protected、private下序列化对象的区别

  • public变量
      -   直接变量名反序列化出来
      •     \x00 + * + \x00 + 变量名

      •     \x00 + 类名 + \x00 + 变量名

       

       

      比较重要的两个方法:

      __sleep()
         serialize() 函数会检查类中是否存在一个魔术方法 __sleep()。如果存在,该方法会先被调用,然后才执行序列化操作。此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组。如果该方法未返回任何内容,则 NULL 被序列化,并产生一个 E_NOTICE 级别的错误。
        对象被序列化之前触发,返回需要被序列化存储的成员属性,删除不必要的属性。


      __wakeup()
        unserialize() 会检查是否存在一个 __wakeup() 方法。如果存在,则会先调用 __wakeup 方法,预先准备对象需要的资源。
        预先准备对象资源,返回void,常用于反序列化操作中重新建立数据库连接或执行其他初始化操作。

       

      绕过__wakeup()

      CVE-2016-7124漏洞,当序列化字符串中表示对象属性个数的值大于真实的属性个数时会跳过__wakeup的执行正常序列化对象后是这样的:↓

      构造序列化对象:O:5:”SoFun”:1:{S:7:”\00\00file”;s:8:”flag.php”;}

      绕过__wakeup:O:5:”SoFun”:2:{S:7:”\00
      \00file”;s:8:”flag.php”;}

  •  Comments