こんにちは, 株式会社ECナビ システム本部 ECナビラボグループの春山(@haruyama)と申します.

私は, 主にセキュリティと検索をテーマに仕事をしています. 今回はセキュリティについてです.

先日, 他の言語については十分経験があるがPHPについてはあまり経験のない社員から,

「PHP (5.2) で使ってはいけない関数の一覧ってどこかにありませんか」と聞かれました.

PHPのセキュリティについては, PHP: セキュリティ - ManualPHP と Web アプリケーションのセキュリティについてのメモなどに資料があります.

また, PHP: PHP 5.3.x で推奨されない機能 - Manual に「推奨されない関数」という項目があります.

PHPのsplit() が推奨されないのは, split() がereg() などの POSIX 正規表現関数に属していて,

そして POSIX 正規表現関数 がバイナリセーフでなく速度も低速であるからです.

この知識はPHPの経験の浅い人が知ることは難しいでしょう.

そこでPHPのコードを静的に解析して問題のある関数の利用を抽出しようと考えました.

PHPの静的解析についてはあまり耳にしませんが, いくつかのツールがあります.

私は前職で, PHPLintという静的解析ツールに手を入れて, 問題のある関数への警告を出していました.

しかし, PHPLintは作者の独自のModula-2風の言語で書かれており, 改造しての利用は手軽ではありません.

そこで, RATS - Rough Auditing Tool for Securityを利用することにしました.

RATSは, c, c++, perl, php, python, rubyに対応した静的解析ツールです.

データベースファイル(xml)を自分で定義することで拡張することができます.

RATSはソースとWin32のバイナリが配布されています.

またDebianやUbuntuにはパッケージもあります.

ソースからのインストールは「./configure; make; make install」で可能です.

Win32のバイナリには, The Expat XML Parserのdllファイルをパスの通った場所に置く必要があります.

RATSのデフォルトのデータベースファイルには, PHPのsplit() についてのルールはありません.

データベースファイル(rats-php-split.xml)を次のように作成します (ファイルの文字エンコーディングやシェルのロケールがUTF-8の場合, 問題なく日本語文字が出力されました).

<VulnDB lang="php">
<Vulnerability>
<Name>split</Name>

<Info>
<Severity>High</Severity>
<Description>
split()はバイナリセーフではありません.
また, preg_split()よりも低速です.
preg_split()かexplode()を使用しましょう.
</Description>
</Info>

</Vulnerability>

</VulnDB>

次のsplit() を利用しているファイル(split_test.php)にRATSを適用すると, データベースファイルで指定した警告が出ます.

<?php
list($user, $pass, $uid, $gid, $extra) =
split(":", $passwd_line, 5);

% .../rats --db rats-php-split.xml split_test.php   
Entries in php database: 1
Analyzing split_test.php
split_test.php:3: High: split
split()はバイナリセーフではありません.
また, preg_split()よりも低速です.
preg_split()かexplode()を使用しましょう.

Total lines analyzed: 6
Total time 0.000074 seconds
81081 lines per second

警告を行なう関数の追加は, Vulnerability要素の追加で行なえます. rats-php-deprecated.xmlが私が作成したPHP: PHP 5.3.x で推奨されない機能 - Manualで挙げられている関数に対するデータベースファイルです.

ECナビでも, PHPを新たに始める人のコードや古いコードのチェックに利用していこうと考えています.

以上, RATSでPHPの利用すべきでない関数をチェックでした.