PHPセキュリティ対策:数値型と制約

(1/1)
PHPセキュリティ対策:数値型と制約
PHPにはデータ型が無いと言われるが、内部的には他の言語と同じくデータ型は存在する。とくに大きな正数/負数を扱う場合には、PHPの制約を超えないように注意する必要がある。
制約を超えると演算が正常に行われなくなり、プログラム全体の動作がおかしくなる場合がある。最悪の場合、プログラムが無限ループに陥ったり、思わぬエラーを晒したりする恐れがあるので、セキュリティ上、注意が必要だ。
PHPで数値を扱う場合には、integer 型(整数型)と float 型(浮動小数型)の2種類に分かれる。両者とも常に符号ありのデータ型である。

(2022年6月27日)FastCGIで正常動作しない不具合を修正

目次

サンプル・プログラム

圧縮ファイルの内容
overflow.phpサンプル・プログラム本体。
pahooInputData.phpデータ入力に関わる関数群。
使い方は「PHPでGET/POSTでフォームから値を受け取る」「数値入力とバリデーション」「文字入力とバリデーション」などを参照。include_path が通ったディレクトリに配置すること。

integer 型の制約

まず、integer 型の制約について見てみよう。

0052: /**
0053:  * integer型のオーバーフローを見る
0054:  * @param   なし
0055:  * @return  なし
0056: */
0057: function overflow1() {
0058:     echo '■integer型のオーバーフロー/アンダーフローを見る<br />';
0059:     echo 'PHP_INT_SIZE = ' . PHP_INT_SIZE . '<br />';    //integer型のバイト長
0060:     echo 'PHP_INT_MAX = '  . PHP_INT_MAX . '<br />'; //integer型の最大値
0061:     echo '<hr />';
0062:     //正数のオーバーフロー
0063:     $a = PHP_INT_MAX - 2;
0064:     for ($i = 0; $i < 5; $i++) {
0065:         var_dump($a);
0066:         echo '<br />';
0067:         $a++;
0068:     }
0069:     echo '<hr />';
0070:     //負数のアンダーフロー
0071:     $a = 0 - PHP_INT_MAX;
0072:     for ($i = 0; $i > -5; $i--) {
0073:         var_dump($a);
0074:         echo '<br />';
0075:         $a--;
0076:     }
0077: }

PHPの integer 型については、組み込み定数 PHP_INT_SIZE がバイト数を、PHP_INT_MAX が正数の最大値を示している。
実際には32ビット環境と64ビット環境で変わり、以下のようになっている。
ビット長PHP_INT_SIZEPHP_INT_MAX
32ビット環境32ビット42,147,483,647
64ビット環境64ビット89,223,372,036,854,775,807


■32ビット環境
PHP_INT_SIZE = 4
PHP_INT_MAX = 2,147,483,647
-231 ≦ integer ≦ 231 - 1
-2,147,483,648 ≦ integer ≦ 2,147,483,647

■64ビット環境
PHP_INT_SIZE = 8
PHP_INT_MAX = 9,223,372,036,854,775,807
-263 ≦ integer ≦ 263 - 1
-9,223,372,036,854,775,808 ≦ integer ≦ 9,223,372,036,854,775,807

プログラムを実行すると、この制約を上回る/下回ると、integer 型から float 型へ自動的に移行するのが分かる。

float型から integer型へは自動移行しない

では、オーバーフローまたはアンダーフローを起こし、integer 型から float 型へ移行してしまったデータ型は自動的に元に戻るか確認しておこう。

0079: /**
0080:  * float型からinteger型へは自動移行しない
0081:  * @param   なし
0082:  * @return  なし
0083: */
0084: function overflow2() {
0085:     echo '■float型からinteger型へは自動移行しない<br />';
0086:     //正数
0087:     $a = PHP_INT_MAX + 2;
0088:     for ($i = 5; $i > 0; $i--) {
0089:         var_dump($a);
0090:         echo '<br />';
0091:         $a--;
0092:     }
0093:     echo '<hr />';
0094:     //負数
0095:     $a = -3 - PHP_INT_MAX;
0096:     for ($i = -5; $i < 0; $i++) {
0097:         var_dump($a);
0098:         echo '<br />';
0099:         $a++;
0100:     }
0101: }

プログラムを実行すると分かるように、いったん float 型へ移行してしまったデータは元の integer 型には自動的に戻らない。この点は注意が必要だ。
もし integer 型にしたいのであれば、強制的にキャストしてやる必要がある。

float 型の制約と誤差

次に、 float 型の制約についてみておこう。

0103: /**
0104:  * float型のオーバーフローを見る
0105:  * @param   なし
0106:  * @return  なし
0107: */
0108: function overflow3() {
0109:     echo '■float型のオーバーフロー/アンダーフローを見る<br />';
0110:     //float型のオーバーフロー(大数側)
0111:     $a = +1.79E+305;
0112:     for ($i = 0; $i < 5; $i++) {
0113:         var_dump($a);
0114:         echo '<br />';
0115:         $a *= 10;
0116:     }
0117:     echo '<hr />';
0118:     //float型のオーバーフロー(小数側)
0119:     $a = +4.94E-323;
0120:     for ($i = 0; $i < 5; $i++) {
0121:         var_dump($a);
0122:         echo '<br />';
0123:         $a /= 10;
0124:     }
0125:     echo '<hr />';
0126:     //float型のアンダーフロー(大数側)
0127:     $a = -1.79E+305;
0128:     for ($i = 0; $i < 5; $i++) {
0129:         var_dump($a);
0130:         echo '<br />';
0131:         $a *= 10;
0132:     }
0133:     echo '<hr />';
0134:     //float型のアンダーフロー(小数側)
0135:     $a = -4.94E-323;
0136:     for ($i = 0; $i < 5; $i++) {
0137:         var_dump($a);
0138:         echo '<br />';
0139:         $a /= 10;
0140:     }
0141: }

float 型の範囲は、PHPの実装に依存する。ただ、大多数の処理系では IEEE 754 規格の倍精度に準拠している。
つまり、絶対値の範囲は下記の通りである。
4.9406564584124654E-324 ≦ float ≦ 1.7976931348623157E+308

これをプログラムで確かめると、この範囲をオーバーフローすると 'INF' または '0' になる、逆にアンダーフローすると '-INF' または '-0' になることが分かる。INFは無限大を意味する。
また、10で除算しているにもかかわらず、2進数特有の“誤差”が発生していることも分かる。

これほどの大きさ/小ささの数値データを扱うことは希だろうが、もしループ処理内でオーバーフロー/アンダーフローしてしまうとINFや0が返るので、PHP処理系ではエラーを出さずに無限ループに陥る恐れがある。注意しておきたいところだ。
(この項おわり)
header