由Hacker News的一个帖来谈谈PHP隐式转换中一些需要注意的点。
由Hacker News的一个帖来谈谈PHP隐式转换中一些需要注意的点。
By lincanbin
at 2015-05-05
2人收藏 • 2726人看过
https://news.ycombinator.com/item?id=9484757
这是Hacker News中的一个帖,里面提及到了一种检测网站加密方式的一种方法:
<?php var_dump(md5('240610708') == md5('QNKCDZO')); var_dump(md5('aabg7XSs') == md5('aabC9RqS')); var_dump(sha1('aaroZmOk') == sha1('aaK1STfY')); var_dump(sha1('aaO8zKZF') == sha1('aa3OFF9m')); var_dump('0010e2' == '1e3'); var_dump('0x1234Ab' == '1193131'); var_dump('0xABCdef' == ' 0xABCdef');
结果都是:
bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true)
也就是说,如果你在一个网站,用240610708作为密码,然后用QNKCDZO登陆,结果可以登录的话,说明密码是以MD5方式保存的,其他同理。
例如如果用最后三项测试能通过,说明网站没有采用任何加密算法,是采用明文保存方式。
这是为什么呢?
以第二对数为例:
<?php var_dump(md5('aabg7XSs')); var_dump(md5('aabC9RqS'));
结果是:
string(32) "0e087386482136013740957780965295" string(32) "0e041022518165728065344349536299"
显然,一眼看上去并不相等,那么为什么var_dump的结果是相等呢?
这是因为PHP是一个弱类型语言,比较的过程中是带有隐式转换的,因为你可以用一个字符串和整数进行比较,字符串会自动转化为整数,例如有这么一张用来黑PHP的图:
var_dump(512=="0512");//结果是true
那么很明显:
string(32) "0e087386482136013740957780965295" string(32) "0e041022518165728065344349536299"
在比较的过程中,因为以0e的科学记数法开头,字符串被隐式转换为浮点数。这两个浮点数因为是0e开头,实际上也就等效于0×10^0,因此比较起来是相等的。有兴趣的可以去查看浮点数的科学记数法相关词条。
其他也是同理。
<?php var_dump(md5('240610708') == md5('QNKCDZO')); var_dump(md5('aabg7XSs') == md5('aabC9RqS'));//字符串被转换为浮点数0E var_dump(sha1('aaroZmOk') == sha1('aaK1STfY')); var_dump(sha1('aaO8zKZF') == sha1('aa3OFF9m')); var_dump('0010e2' == '1e3');//10×10^2 = 1×10^3 var_dump('0x1234Ab' == '1193131');//十六进制与整数,被转换为同一进制比较 var_dump('0xABCdef' == ' 0xABCdef');//十六进制数与带空格十六进制数,被转换为十六进制整数
如何避免这种隐式转换呢?
使用“===”比较符则可以避免,这是一个除了检查值还检查类型的比较符号,也就基本等效于强类型语言中的“==”。
来测试一下:
<?php var_dump(md5('240610708') === md5('QNKCDZO')); var_dump(md5('aabg7XSs') === md5('aabC9RqS')); var_dump(sha1('aaroZmOk') === sha1('aaK1STfY')); var_dump(sha1('aaO8zKZF') === sha1('aa3OFF9m')); var_dump('0010e2' === '1e3'); var_dump('0x1234Ab' === '1193131'); var_dump('0xABCdef' === ' 0xABCdef');
结果:
bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false)
所以呢,PHP中的Hash校验,应该除了值,还要检验类型,也就是要使用“===”,而不应该使用“==”。
另外如果生产环境版本足够高的话,最好使用hash_equals()
林灿斌写于2015年5月5日凌晨。
- 登录后方可回帖
2 个回复 | 最后更新于 2015-05-05