たとえば、if(0.5+0.2==0.7) の結果は false になります。その理由は、PHP は C 言語に基づいており、C 言語はバイナリ シンボル ポイントの表現のため、ほとんどのシンボル ポイントを正確に表現できないためです。実際、ほとんどすべてのプログラミング言語は小数点 (ドット付き数字) を正確に表現できません。これは IEEE 754 の欠陥であるためです。この問題を解決するには、別の標準を確立するしかありません。この問題を解決できるのは Mathematica だけのようです。
なぜ?この比較は弱い型指定であるため、2 つの比較が行われると、PHP はまず左側と右側が数値であるかどうかを判断しようとします。問題は、数値とはどのような種類の文字列なのかということです。それは単純な数値の文字列ですか?さらに、0x で始まる 16 進数、XXeX 型の科学表記法なども含まれます。たとえば、「12e0」==「0x0C」は true になります。 数値型と文字列を比較する場合、12=='the string 12' など、数字で始まる一部の非数値文字列も true になります。
したがって、このような場合、同じではない文字列が等しいと判断される可能性があります。 === を使用した比較は、変換を行わない包括的な型の比較であるため、文字列が同じかどうかを正確に比較できます。
あと、JAVAの==では文字列がオブジェクトであるため、文字列が等しいかどうかの比較ができず、==が同じオブジェクトかどうかの判断になってしまうことにも文句を言いたいのですが…。
4. インターネット上で言及されているクライアント IP アドレスを取得するさまざまな方法
这函数看起来并没有什么问题,很多开源CMS之类的也在用。然而事实上,问题大着呢!首先第一步,是要了解这些 getenv 读取的东西到底是什么玩意,又是从哪来的。简单来说这些其实是HTTP header,有些代理服务器会把源请求地址放到header里,所以我们服务器可以知道访问用户的原始IP地址。但是,并不是所有代理服务器都会这么做,也并不是只有代理服务器会这么做。
而实际上,这些HTTP header是可以随便改动的,比如curl就可以自己设置各种HTTP header。如果用此函数得到的结果,进行IP限制等操作的话是很轻易绕过的。更可怕的是,如果后续程序没有对此函数取得的IP地址进行格式校验过滤的话,就很微妙地为SQL注入打开了一扇窗户。所以比较保险的方式是只读取非HTTP header的 $_SERVER['REMOTE_ADDR']
PHP5.4及以上可以使用以下函数判断是否符合IP地址格式 filter_var($ip, FILTER_VALIDATE_IP) ,老版本需自行写正则。
五、foreach的保留现象
使用 foreach($someArr as $someL){ } 之类的用法时,要注意最后的一个 $someL 会一直保留到该函数/方法结束。而当使用引用的时候 foreach($someArr as &$someL){ }这是以引用来保存,也就是说后面若有使用同一个名字的变量名,将会把原数据改变(就像一个乱用的C指针)。为安全起见,建议每个foreach(尤其是引用的)结束之后都使用unset把这些变量清除掉。
foreach($someArr as &$someL){ //doSomething ...}unset($someL);
六、htmlspecialchars 函数默认不转义单引号
不少网站都是使用此函数作为通用的输入过滤函数,但是此函数默认情况是不过滤单引号的。这是非常非常地容易造成XSS漏洞。这样的做法和不过滤双引号没太大区别,只要前端写得稍微有点不规范(用了单引号)就会中招。下面这个示例改编自知乎梧桐雨的回答4110a9844baef9d25a82ccef3094ed14
要求所有的时候都使用双引号不得使用单引号,这其实不太现实。所以,这个主要还是后端的责任,把单引号也要转义,我们用的时候一定要给这个函数加上参数 htmlspecialchars( $data, ENT_QUOTES);
很多人向Thinkphp框架提出过这个问题,因为其默认过滤方法就是无参数的htmlspecialchars,不过滤单引号,而其官方答复是“I函数的作用不能等同于防止SQL注入,可以自定义函数来过滤”……毛线啊,最基本的防护都不给力,这是给埋了多少隐患啊。在此强烈各位使用者重新定义默认过滤函数,我自己定义的是 htmlspecialchars(trim($data), ENT_QUOTES); ,有更好建议欢迎评论。同时非常希望TP官方更正此问题。
关于XSS,容我多说两句,请看下面这个例子。
<span style="color:#ff00ff;"><?</span><span style="color:#ff00ff;"><span style="color:#000000;"><span style="color:#ff00ff;">php</span> $name='alert(1)';</span> </span><span style="color:#ff00ff;">?></span><span style="color:#0000ff;"><</span><span style="color:#800000;">p </span><span style="color:#ff0000;">id</span><span style="color:#0000ff;">="XSS2"</span><span style="color:#0000ff;">></</span><span style="color:#800000;">p</span><span style="color:#0000ff;">></span><span style="color:#0000ff;"><</span><span style="color:#800000;">script </span><span style="color:#ff0000;">src</span><span style="color:#0000ff;">="//cdn.batsing.com/jquery.js"</span><span style="color:#0000ff;">></</span><span style="color:#800000;">script</span><span style="color:#0000ff;">></span><span style="color:#0000ff;"><</span><span style="color:#800000;">script</span><span style="color:#0000ff;">></span><span style="background-color:#f5f5f5;color:#000000;">$(</span><span style="background-color:#f5f5f5;color:#000000;">"</span><span style="background-color:#f5f5f5;color:#000000;">#XSS2</span><span style="background-color:#f5f5f5;color:#000000;">"</span><span style="background-color:#f5f5f5;color:#000000;">)[</span><span style="background-color:#f5f5f5;color:#000000;">0</span><span style="background-color:#f5f5f5;color:#000000;">].innerHTML </span><span style="background-color:#f5f5f5;color:#000000;">=</span> <span style="background-color:#f5f5f5;color:#000000;"><?=</span><span style="background-color:#f5f5f5;color:#000000;">$name</span><span style="background-color:#f5f5f5;color:#000000;">?></span><span style="background-color:#f5f5f5;color:#000000;">;
$("#XSS2").html( <?=$name?> );
$(</span><span style="background-color:#f5f5f5;color:#000000;">"</span><span style="background-color:#f5f5f5;color:#000000;">#XSS2</span><span style="background-color:#f5f5f5;color:#000000;">"</span><span style="background-color:#f5f5f5;color:#000000;">)[</span><span style="background-color:#f5f5f5;color:#000000;">0</span><span style="background-color:#f5f5f5;color:#000000;">].innerHTML </span><span style="background-color:#f5f5f5;color:#000000;">=</span> <span style="background-color:#f5f5f5;color:#000000;">"</span><span style="background-color:#f5f5f5;color:#000000;"><?=$name?></span><span style="background-color:#f5f5f5;color:#000000;">"</span><span style="background-color:#f5f5f5;color:#000000;">;
$("#XSS2").html(" <?=$name?> ");</span><span style="color:#0000ff;"></</span><span style="color:#800000;">script</span><span style="color:#0000ff;">></span>
JS の 1 行目と 2 行目は XSS 脆弱性を引き起こしますが、3 行目と 4 行目は脆弱性を引き起こしません。 alert(1) に関しては、バックエンドでこのような文字列をフィルタリングするより良い方法はありません。唯一の効果的な方法は、データの両端に引用符を追加することです。 innerHTML と jQuery の html() の出力を使用する場合、主な責任は依然としてフロントエンドにあります。渡されるパラメーターが string であることを必ず確認してください。それ以外の場合は、いいえです。 eval 関数 よりも危険性が低い