入力処理とセキュリティ
入力値の検証とセキュリティ
入力値の検証の目的はセキュリティ対策ではないが、以下のようにセキュリティのために役立つ場合もある。
- SQLインジェクション対策が漏れていたが、英数字のみ許可していたので実害には至らない。
- バイナリセーフではない関数を使っているが、入力段階で制御文字をチェックしているので実害には至らない。
- 表示処理の関数で文字エンコーディングの指定を怠っているが、入力段階で不正な文字エンコーディングをチェックしているので実害には至らない。
バイナリセーフ
バイナリセーフとは入力値がどんなバイト列であっても正しく扱えることを意味する。典型的な例としてはヌルバイト(PHPでは\0と表記)が現れても正しく処理できることを指す。
ヌルバイトが特別な理由は、CおよびUNIX、WindowsのAPIでヌルバイトを文字列の終端とみなす取り決めがあるからである。このためPHPやその他の言語ではヌルバイトを正しく扱えない関数がある。このような関数をバイナリセーフではない関数と言う。
ヌルバイトを使った攻撃手法はヌルバイト攻撃と呼ばれる。ヌルバイト攻撃は他の脆弱性対策を回避するために使用される。
ヌルバイト攻撃との組み合わせが多い脆弱性はXSS脆弱性、ディレクトリトラバーサル脆弱性がある。
下記のPHPのコードはereg()を用いて変数$pが数字のみからなることを検証している。
ereg()はバイナリセーフではない。
<?php $p = $_GET['p']; if (ereg('^[0-9]+$', $p) === FALSE) { die('整数値を入力してください。'); } echo $p; ?>
これに以下のURLでアクセスする。
http://example.jp/42/42-002.php?p=1%00<script>alert('XSS');</script>
結果はブラウザ上でjavascriptが実行されダイアログ上に「XSS」と表示される。これはヌルバイト攻撃+XSS脆弱性である。
URL中の「%00」はヌルバイトであり、ereg()はヌルバイトで文字列が終わっているとみなすためヌルバイトより後ろを無視し、検証が回避された。
ヌルバイト攻撃に対する根本対策はバイナリセーフの関数のみを用いてアプリケーションを開発することである。しかし、言語の関数リファレンスには関数がバイナリセーフかどうか記述がない場合が多く、現時的には困難である。
そのため、アプリケーションの入り口でバイナリセーフの関数を用いてヌルバイトをチェックするのが現実的な対応である。
入力値の検証基準はアプリケーション要件
入力値の検証の基準はアプリケーション要件である。
よって「すべての文字を許可する」という場合もある。しかし、そのような場合でも以下のチェックは行うべきである。
- 制御文字のチェック
- 文字数のチェック
PHPの正規表現ライブラリ
PHPの正規表現関数にはereg、preg、mb_eregの3系統がある。
eregは前述のとおりバイナリセーフではないので、開発ではpreg、mb_regを使用する。
pregはエンコードがUTF-8の場合のみ日本語を扱える。mb_eregは様々なエンコーディングが利用できる。
下記は英数字1~5文字チェックをpreg_match()で実装したコードである。
データの先頭と末尾はそれぞれ'\A'と'\z'で示す。代わりに'^'と'$'を使う場合もあるが'^'と'$'は行の先頭と末尾を表すので、'^'と'$'を使うと改行文字がチェックを通過してしまう。
<?php $p = isset($_GET['p']) ? $_GET['p'] : ''; if (preg_match('/\A[a-z0-9]{1,5}\z/ui', $p) == 0) { die('1文字以上5文字以下の英数字を入力してください'); } ?>
文字種の制限がなし1~30文字の場合は、preg_match()の部分は以下のようになる。
preg_match('/\A[[:^cntrl:]]{1,30}\z/u', $p)
また、textarea要素からの入力値で改行、タブを許容し他の制御文字は禁止する場合は以下のようになる。
preg_match('/\A[\r\n\t[:^cntrl:]]{1,30}\z/u', $p)
「[:cntrl:]」は制御文字を表すPOSIX文字クラスで、「[:^cntrl:]」はその否定、つまり制御文字以外である。
参考文献:体系的に学ぶWebアプリケーションの作り方 4.2 入力処理とセキュリティ
体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践 徳丸 浩 ソフトバンククリエイティブ 2011-03-03 売り上げランキング : 4070 Amazonで詳しく見る by G-Tools |
« PostgreSQLでMySQLのgroup_concat関数のようなことをする | Main | jQueryで非同期な処理が終わるのを待つにはDeferredを使う »
「プログラミング、技術情報」カテゴリの記事
- PHPStorm 2018.1.7 に更新(2018.12.09)
- 技術メモをQiitaに移行(2016.01.24)
- 正規表現メモ:ものぐさ(最小)マッチング(2015.11.29)
- BASE64にエンコード/デコードするバッチファイル(2015.11.23)
- Windows7の検索ボックスの検索条件指定(フォルダの除外など)(2015.08.16)
「PHP」カテゴリの記事
- PHPStorm 2018.1.7 に更新(2018.12.09)
- PHPメモ051:includeとrequireの使い分け(2015.06.19)
- CakePHPのインストール(2015.06.14)
- PHPからPDOでPostgreSQLに接続する(2015.06.09)
- PHPでメールを送信したら一部のOutlookで受信したメールでヘッダがおかしくなった(2015.05.31)
「セキュリティ」カテゴリの記事
- PHPメモ041:パスワードのSalt付きハッシュ値(2014.08.09)
- ファイルインクルード脆弱性(2014.05.18)
- ファイルダウンロードによるXSS その3(2014.03.27)
- ファイルダウンロードによるXSS その2(2014.03.23)
- ファイルダウンロードによるXSS その1(2014.02.24)
The comments to this entry are closed.
« PostgreSQLでMySQLのgroup_concat関数のようなことをする | Main | jQueryで非同期な処理が終わるのを待つにはDeferredを使う »
Comments