由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方式保存的,其他同理。

例如如果用最后三项测试能通过,说明网站没有采用任何加密算法,是采用明文保存方式。

http://3v4l.org/tT4l8

这是为什么呢?

以第二对数为例:

<?php
var_dump(md5('aabg7XSs'));
var_dump(md5('aabC9RqS'));

结果是:

string(32) "0e087386482136013740957780965295"
string(32) "0e041022518165728065344349536299"

显然,一眼看上去并不相等,那么为什么var_dump的结果是相等呢?

这是因为PHP是一个弱类型语言,比较的过程中是带有隐式转换的,因为你可以用一个字符串和整数进行比较,字符串会自动转化为整数,例如有这么一张用来黑PHP的图:

7c496fb39f364a3379e3ad129a6f3e5a_r.jpg

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
oojiayu
2015-05-05
#1

PHP是世界上最优秀的语言……你这是在拉仇恨啊~

还好~ 我不是程序员~ 我只是老板~

lincanbin
2015-05-05
#2

回复#1 @oojiayu :

隐式转换我觉得也算PHP的优点了,并且不想要隐式转换的时候,也可以用其他语法来进行没有隐式转换的比较。


登 录


现在注册

QQ  登 录    Weibo  登 录    GitHub  登 录