常用知识 - 字符串与数字0比较要注意

    xiaoxiao2021-03-25  150

    先看代码:

    var_export([ 'a == 0' => 'a' == 0, //true 'abcd == 0' => 'abcd' == 0, //true '中文 == 0' => '中文' == 0, //true 'a1 == 0' => 'a1' == 0, //true 'a123456 == 0' => 'a123456' == 0, //true '===接下来数字开头===' => '============', '0a == 0' => '0a' == 0, //true '012a == 0' => '012a' == 0, //false '012a == 12' => '012a' == 12, //true '012a == 0' => '012a' == 0, //false '123 == 0' => '123' == 0, //false '123 == 123' => '123' == 123, //true ]);

    运行结果:

    结论:字母开头的字符串 与 数字0 用 == 模糊比较总是true

    详解

    不管是'a' == 0还是0 == 'a',只要是两个比较值中有一个是数字,而另一个是字符串,那么PHP会先自动将字符串转换成一个数字,然后再与数字比较,由于a这个字符串转成数字后的值是0,所以最终变成了0 == 0结果就成了true


    带来的坑

    例子:

    $age = $_POST['age']; // 8a if($age <= 0){ exit('请输入修改的年龄'); } $db->insert('user', ['age' => $age]);

    这样数据库就会构建成一个无效的插入语句报错了

    再假设一下如果$age的值如果是8 or 1 = 1,然后执行查找会怎样?

    $age = $_POST['age']; // 8a if($age <= 0){ exit('请输入修改的年龄'); } $db->select('user', ['age' => $age]); //如果没用PDO参数绑定或者其它参数化查询,底层直接简单拼字符串的话绝对会这样: SELECT * FROM `user` WHERE age = 8 or 1 = 1 //还有的用了框架的人都途方便,这样写: (new \yii\db\Query())->from('user')->where('age = ' . $age)->one(); //有注入漏洞,其它框架就不举例子了 //这样写where条件才安全 (new \yii\db\Query())->from('user')->where(['age' => $age])->one(); //注入会失败,

    你懂的,主要是这个数字开头的注入字符串绕过了比较逻辑

    看你还敢不敢随便拼字符串条件?能用数组条件就尽量用数组条件,一般框架的底层都会做好注入过滤和参数化查询这些事情


    这只是拿注入攻击来举个例子,不止是注入,光是让你程序跑出错都有很多种可能,试想,一个我们本应预期是数字的值,居然成了字符串然后被流通到后面的环节中,肯定存在很多影响计算结果的可能性,所以在源头就应该确保它是数字

    解决办法

    当然是将 == 比较符写成 === 啦

    但要注意这其实只是第一思考结果,但实际上程序员们都习惯了写==号,所以不能保证所有团队成员或者新加入员工都能这样去写===的严格比较

    并且你也基本没办法每处都检查他的比较符号有没有写对

    将请求参数强制转换

    我的做法通常都是在接收前端参数时就将它强转成int:

    $age = (int)$this->post('age'); //获取$_POST['age'];

    这样就算传来字符串也会被转成数字类型,就当它是那个数字处理咯,要不就用is_numerice这些函数进行严格的内容验证,自己看性价比取舍,但这个防御要有!

    下面是我项目中的一些例子,也强制性要求项目成员收参数时必须按照相关类型先强行转换

    转载请注明原文地址: https://ju.6miu.com/read-2716.html

    最新回复(0)