【发布时间】:2011-03-25 17:13:53
【问题描述】:
我可能听起来有点奇怪,但是,有什么办法吗?例如,我有一个 PHP 对象$foo。
有没有办法通过一些对象加密函数将这个对象存储在 HTML 表单(隐藏输入)中,然后用解密函数检索。
同样,我可以通过 GET 方法传递这些对象吗?
【问题讨论】:
我可能听起来有点奇怪,但是,有什么办法吗?例如,我有一个 PHP 对象$foo。
有没有办法通过一些对象加密函数将这个对象存储在 HTML 表单(隐藏输入)中,然后用解密函数检索。
同样,我可以通过 GET 方法传递这些对象吗?
【问题讨论】:
就像其他地方已经指出的那样,您可以使用序列化将对象转换为字符串。
$foo = (object) array(
'foo' => 'foo & bär',
'bar' => new StdClass
);
$serialized = serialize($foo);
这给出了:
O:8:"stdClass":2:{s:3:"foo";s:10:"foo & bär";s:3:"bar";O:8:"stdClass":0:{}}
如您所见,该字符串中有引号,因此您不能将其插入链接而不冒破坏标记的风险:
<a href="http://example.com?s=O:8:" <-- quote closes href
所以至少你必须htmlspecialchars 或urlencode 那个输出。但是,这仍然会使内容易于阅读。您可以使用PHP's MCrypt library 对字符串进行一些强加密。但如果数据真的那么敏感,您可能应该找到另一种传输方式,远离您网站的面向公众的部分。
如果数据不那么敏感,那么您可以通过混淆字符串来保护一些 CPU 周期。最简单的方法是通过gzdeflate 运行它:
echo gzdeflate(serialize($foo));
给出类似的东西
?R*.Iq�I,.V�2��.�2�RJ��W�.�24 …
使用gzdeflate 也会缩短大的序列化字符串。缺点是,它会产生不适合通过 HTTP 传输的输出,因此您还必须 base64_encode 表示:
echo base64_encode(gzdeflate(serialize($foo)));
然后会给出
87eysFIqLklxzkksLlayMrKqLrYytlJKy89Xsi62MjQAMxXUFJIOLykCiQDlkhKBLH9UfQZW1bW1AA==
这对于传输是安全的,并且与原始序列化字符串相比也相当模糊。因为我们在对字符串进行 base64 处理之前已经对其进行了压缩,所以任何聪明到能确定它是 base64 的人在尝试反转压缩字符串时仍然必须理解压缩字符串。
要将字符串转回一个对象,你可以这样做
unserialize(
gzinflate(
base64_decode(
$obfuscatedString
)
)
)
然后取回你的对象。 Demo
关于安全性的说明
以上内容仍然不安全。您不应该依赖混淆来确保安全。如果通过 HTTP 传输一个对象或整个对象图,则必须将它们视为接收端的用户输入。 用户输入不可信。弄清楚字符串是如何被混淆的恶意用户可以提供更改的输入。因为您要将对象反序列化回程序流中,所以您必须对生成的对象绝对偏执。
有关相关示例,请参阅 http://www.sektioneins.com/en/advisories/advisory-032009-piwik-cookie-unserialize-vulnerability/。
【讨论】:
如果它不包含敏感数据,你可以serialize()它(甚至可以选择加密序列化数据),例如:
<input type="hidden" name="foo" value="<?php echo htmlspecialchars(serialize($foo), ENT_QUOTES); ?>" />
在接收脚本中,unseralize()将POST数据取回对象:
$foo = unserialize($_POST['foo']);
【讨论】:
htmlspecialchars(serialize($foo))。要在 PHP 中获取值,您需要先将该表单发送到 PHP,然后您可以通过 unserialize($_POST['foo'])(或 unserialize($_GET['foo']),如果您通过 GET 发送)读取它 - 但是请注意,unserialize() 已经暴露了安全问题如果我没记错的话在过去,所以这可能很危险,您还必须检查反序列化是否真的有效。
您可以使用serialize 和unserialize 方法:
$serialized = serialize($foo);
现在您可以将$serialized 存储在隐藏的输入字段中。稍后,您可以将其读回并使用unserialize 方法转换为对象。例如:
$foo = unserialize($_POST['my_hidden_field']); // back to object
【讨论】: