====== 整数値のオーバーフローを検出/防止する ====== PHPの整数型はCPU/OSによって異る * 64 bit OS - 整数型は符号付き64bit整数 (ただし、Windowsは7.0未満は符号付き32bit整数) * 32 bit OS - 整数型は符号付き32bit整数 浮動小数点型はIEEE754の倍精度浮動小数点型で符号付き53bit整数まで正確に表現できる。 厳密な整数型の利用が必要な場合は整数値のオーバーフローを検出、防止が必要となる。特に外部システムとデータをやり取りする場合に、データ型と範囲の違いに注意しなければならない。整数型には符号付きと符号無し整数の2種類がある。PHPは符号付き整数型のみサポートするので、符号無し整数を取り扱う場合にも注意が必要である。 ここではRDBMSのPostgreSQLを例として利用する。しかし、データ型を持つシステム(PHPを含む)の場合はオーバーフローする場合の取り扱いに注意しなければならない。非適合コード、適合コードは以下のテーブル定義を持つデータベースとする。 CREATE TABLE sample ( id SERIAL NOT NULL, -- SERIAL is signed 32 bit integer int4 INT, -- INT is signed 32 bit integer int8 INT8 -- INT8 is signed 64 bit integer ); ※ PostgreSQLは16/32/64bit符号付き整数型のみサポートする。MySQLは明示的に指定し符号無し整数型を利用できる。 ===== 非適合コード例 ===== このコードは32bit/64bit OS両方のPHPでクエリに失敗する。 エラー例 Warning: pg_query_params(): Query failed: ERROR: value "9223372036854775" is out of range for type integer in - on line 10 Fatal error: Uncaught Exception: Query failed in -:12 Stack trace: #0 {main} thrown in - on line 12 ===== 適合コード例 ===== PHPで整数オーバーフローを検出するのは比較的簡単である。PHPは整数オーバーフローを起こす場合は自動的に浮動小数点型に変換される。64bit環境では符号付き32bit整数の範囲外であるか、のチェックも必要である。 0xEFFFFFFF) { throw new Exception('32 bit integer overflow'); } $sql = 'INSERT INTO sample (int4, int8) VALUES ($1, $2)'; $ret = pg_query_params($sql, [$myint, $myint]); if ($ret === FALSE) { throw new Exception('Query failed'); } ?> ===== 例外 ===== DBMSなど、外部システムの整数オーバーフローエラーに頼れる場合は外部システムのエラーに頼っても構わない。だたし、他の出力先への出力する場合は先に外部システムに出力してエラーを確認しなければならない点に注意する。 ===== リスク評価 ===== 入力を受け付けた時点または計算を行った時点でチェックしないとシステムで常にエラーが発生し、サービス提供が不能になる場合も考えられる。 ^ Rule ^ Severity ^ Likelihood ^ Remediation Cost ^ Priority ^ Level ^ | IDS05-J | medium | unlikely | high | P4 | L3 | ===== 関連ガイドライン ===== ===== 参考文献 ===== * https://blog.ohgaki.net/checking-php-int-type-overflow-underflow * https://blog.ohgaki.net/computers-cannot-handle-numeric-value-correctly * https://blog.ohgaki.net/php7-type-hint-problem-with-int-and-float