编码安全指南
编程本身就应该是一门艺术, 而安全编程更是一种在刀尖上舞蹈的艺术, 不仅要小心脚下的锋利寒刃, 更要小心来自网络黑客或攻击者的狂轰乱炸.
- by code artist
1.hash 比较的缺陷
经过试验发现, 当 Hash 值以 "0e" 开头且后面都为数字, 当和数字进行比较的时候总会被判断和 0 相等
例如:
var_dump('0e1327544' == 0); // bool(true)
当密码被 md5 计算后, 可能会以 "0e" 开头, 下面这个例子可以绕过密码验证.
经过我的验证 PHP 7.1.x 后没有这种问题.
- <?PHP
- $password_from_db = "0e23434";
- $password = "2323"; // 随意的一个密码. 来自 $_POST, 即表单提交
- if ($password_from_db == md5($password)) {
- echo "login success!";
- } else {
- echo "login fails";
- }
更安全的 hash 比较:
可以使用内置函数 hash_equals()来比较 hash 值.(PHP 版本必须是 5.6 及其以上)
- if (hash_equals($password_from_db, md5($password)) {
- .....// other logic
- }
2.bool 比较的缺陷
json_decode 和 unserialize 函数可能将部分结构解析成 bool 值, 造成一些比较上的缺陷.
先举例 json_decode 的案例:
- <?PHP
- $str = '{"user":true,"pass": true}';
- $data = json_decode($str, true);
- if ($data['user'] == 'root' && $data['pass'] == 'pass') {
- echo "login success\r\n";
- } else {
- echo "login fails\r\n";
- }
执行结果为: login success
这样利用 bool 比较的漏洞就绕过了登录或者授权验证.
unserialize 过程相逆, 结果类似, 也会出现安全问题.
正确的做法还是使用 "===" 来进行比较, 这不光是 PHP, 包括一些其他脚本语言或者静态语言, 都请严谨地使用全等于符号进行比较.
3. 数值比较
PHP 虽然是弱类型语言, 但是数据类型也有数值范围. 对于整型而言, 最大值为 PHP_INT_MAX(即 9223372036854775807)
攻击者可以利用最大值越界, 绕过一些验证, 如登录, 账号充值等等.
举例:
- $a = 9223372036854775807;
- $b = 9223372036854775827;
- var_dump($a === $b); // bool(true)
- var_dump($a % 100); // int(0)
由此, 可见全等号 (===) 也不是万能的, 具体场景下要更小心. 经验证, php7.1.x 后不会出现该问题, 5.x 的可能出现.
在实际业务逻辑里面一定要注意判断最大值问题, 避免越界带来的问题.
当使用超长浮点数变量的时候, PHP 也会出错.
- <?PHP
- $uid = 0.999999999999999999;
- if ($uid == "1") {
- echo "search uid is 1 for data\r\n"; // 这里 PHP 将 $uid 约等于 1 了, 进入该判断条件里的逻辑
- }
同理, 2.999999999999 也会被当成 3, 这就是超越浮点数精度造成的偏差.
解决办法有很多, 最简单的就是用 is_int()函数进行判断, 如果不是整型, 则报错或做错误处理.
4.switch 缺陷
当用 case 判断数字的时候, switch 会把参数转换成 int 类型进行计算, 代码如下:
- <?PHP
- $num = "1FreePHP";
- switch ($num) {
- case 0: echo "nothing";
- break;
- case 1: echo "1 hacker here!";
- break;
- case 2: echo "2 hackers here";
- break;
- default:
- echo "confused";
- }
最后输出: 1 hacker here!
所以, 请使用 is_numeric()函数进行判断, 保证数据类型如预期的一致.
5. 数组缺陷.
in_array()和 array_search()函数在没有使用严格模式的情况下会用松散比较, 可能造成一些错误.
例如:
- <?PHP
- $arr = [0, 2, 3, "4"];
- var_dump(in_array('freephp', $arr)); // true
- var_dump(array_search('freephp', $arr)); // 0: 下标
- var_dump(in_array('2freephp', $arr)); // true
- var_dump(array_search('3freephp', $arr)); // 2: 下标
总的来说, PHP 工程师对于这种弱类型语言的使用上要更加小心, 虽然平时写起业务来 "短平快", 但安全编程也不要忘记, 能用上 hint 的高版本 PHP 就进行标注清楚入参, 出参, 让 PHP 代码更加健壮.
来源: https://www.cnblogs.com/freephp/p/11945206.html