那些年php编程犯过的错(1)
此前在一家公司工作的时候犯了一个错,是从事编程以来犯得最严重的错,一辈子难忘呀。听我细细道来,那时公司有一款新游戏发布,在公测前需要找一批玩家来参加内测,于是就有了发号这样一个流程。其实就是让玩家先来登记一下,然后管理人员从中筛选出一批人员,然后给他们发一个激活码。激活码通过邮箱发送给玩家后,他们再到网站上用邮件里的激活码激活他们的账号。
流程还算简单。我当时的程序是像下面这样写的:
[*]$salt = "!@#$%^&";
[*]
[*]$user_id = !empty($_GET['uid'])?(int)$_GET['uid']:0;
[*]$code = !empty($_GET['c'])?$_GET['c']:0;
[*]//echo md5($salt .'+'. $user_id);
[*]if(md5($salt .'+'. $user_id) != $code)
[*]{
[*] echo("no");
[*]}
[*]else
[*]{
[*] echo("yes");
[*]}
一眼看上去好像也没有什么问题吧?当时我也是这么想的。
让我们来分析一下:
程序接收两个参数,一个uid即用户ID,一个c即激活码。
然后通过salt与user_id连接后的md5值与激活码是否相等来判断用户的参数是否正确,进而完成用户的激活。
真的是没有什么技术含量,于是简单的测试了一下。
假如我们的用户ID是3,则md5($salt.'+'.3)之后的值为:
[*]e24fc053f0392e6ac322627d07a568ba
在地址栏中我们输入:
[*]localhost/test.php?uid=3&c=e24fc053f0392e6ac322627d07a568ba
访问后的输出为:yes
一切正如我所期望的那样,太完美了!
程序很快就上线运行了。一开始都工作正常,但是数小时之后,客服反馈有异常情况:一些没有资格的用户也成功激活了。
一开始我还不信,怎么可能呢?程序怎么可能被绕过呢?程序上线之前还交由测试部门测过的呀。
后来通过访问日志了解到了玩家详细的激活流程,只能感叹:劳动人民的智慧是无穷的呀!
他们是这样干的,地址如下:
[*]http://localhost/test.php?uid=3&ce24fc053f0392e6ac322627d07a568ba
看出区别来了么?注意&后面,是的,c后面的"="没了。
这样访问后的输出结果的确是:yes。
这是怎么回事?
来分析一下吧:
当等号没有了就相当于c参数没有了,此时,程序中的$code将会默认为0。而我们知道md5的返回值是一个字符串,当一个字符串与0作比较时将会进行隐式的类型转换。杯具的字符串将会转换成0,使得if判断被绕过,进而完成了激活。
知道了问题,解决的办法就简单了,最简单的办法就是用恒等来进行判断:
[*]if(md5($salt .'+'. $user_id) !== $code)
当然也可以用strcmp来判断,或是将$code默认为空字符也行。
当天晚上通宵加班对程序进行了修改,直到凌晨5点成功发布上线,并确认没有bug后才回家休息。
总结:在进行字符串比较时,一定要注意类型,用恒等或strcmp来判断是最安全的。
页:
[1]