レシピ201のバグおよび脆弱性について

IE 6,7,8でPNGおよびJPEG画像がアップロードできない

[レシピ201] 複数の画像ファイルをアップロードしたい(P.502~)に、IE 6,7,8でPNGおよびJPEGの画像がエラーになりアップロードできないというバグがありました。

なお、本書の動作環境はFirefox 3.0およびIE 6 SP2、IE 7です。

確認したところ、原因は、IE 6,7,8では送信されるMIMEタイプが

  • PNGの場合、image/x-png
  • JPEGの場合、image/pjpeg

ですが、getimagesize()関数が返すMIMEタイプは、

  • PNGの場合、image/png
  • JPEGの場合、image/jpeg

であり、これらを単純に比較して一致するか確認するという誤った検証ロジックになっていたためです。

これに対する修正は以下のようになります。

--- 06/06/02.php (リビジョン 2810)
+++ 06/06/02.php (リビジョン 2811)
@@ -29,10 +29,15 @@
}
# getimagesize()関数で画像かどうかの判定をします。
$checkImage = @getimagesize($_FILES['uploadfile']['tmp_name'][$i]);
+ $type = $checkImage[2]; // 画像タイプを取得
if ($checkImage == FALSE) {
$error .= '画像ファイルをアップロードしてください
';
- } else if ($imgType != $checkImage['mime']) {
+ } else if ($extension == 'gif' && $type != IMAGETYPE_GIF) {
$error .= '拡張子が異なります
';
+ } else if ($extension == 'png' && $type != IMAGETYPE_PNG) {
+ $error .= '拡張子が異なります
';
+ } else if ($extension == 'jpg' && $type != IMAGETYPE_JPEG) {
+ $error .= '拡張子が異なります
';
} else if ($_FILES['uploadfile']['size'][$i] > 102400) {
# 画像ファイルのサイズ上限をチェックします。
$error .= 'ファイルサイズが大きすぎます。100KB以下にしてください
';

getimagesize()関数の返す「画像タイプ」の情報を使い、送信されたMIMEタイプと実際の画像タイプが一致するか検証するように変更しています。

ファイル名の衝突の可能性による脆弱性

また、ファイル名の生成に現在時刻(秒単位)を使っているのでファイル名の衝突の可能性あるとのご指摘がありました。

確認したところ、ファイル名が秒単位でユニークになるという命名ロジックになっており、秒単位で同じ時刻に同時に2人がファイルをアップロードした場合、後からアップロードされたファイルで上書きされます。

これに対する修正は以下のようになります。

--- 06/06/02.php (リビジョン 2811)
+++ 06/06/02.php (リビジョン 2812)
@@ -48,8 +48,8 @@
# 画像ファイルの拡張子をチェックします。
$error .= 'アップロード可能なファイルはgif、jpgまたはpngのみです
';
} else {
-# ここでは格納ディレクトリの下に「"upfile_" + 現在のタイムスタンプ + 連番 + 拡張子」で配置します。
- $moveTo = $filePath . '/upfile_' . time() . $i . '.' . $extension;
+# ここでは格納ディレクトリの下に「"upfile_" + 現在のタイムスタンプ + 連番 + "_" + マイクロ秒と元ファイル名とアクセス元IPアドレスに基づくMD5 + 拡張子」で配置します。
+ $moveTo = $filePath . '/upfile_' . time() . $i . '_' . md5(microtime() . $_FILES['uploadfile']['name'][$i] . $_SERVER['REMOTE_ADDR']) . '.' . $extension;
# アップロードした一時ファイルを指定した場所へ移動します。
if (!move_uploaded_file($_FILES['uploadfile']['tmp_name'][$i], $moveTo)) {
$error .= '画像のアップロードに失敗しました
';

ファイルの命名規則を変更し、現在のマイクロ秒と元ファイル名、アクセス元のIPアドレスに基づくMD5の値をファイル名に追加することで、秒単位で同じ時刻にアップロードされた場合でもファイル名が衝突しないように修正しています。

クレジット表示

これらのバグは、HASHコンサルティング株式会社 徳丸 浩さまにより報告されました。

kenji posted at 2011-9-21 Category: 追加情報

Trackback URL

One Response Leave a comment

  1. […] レシピ201のバグおよび脆弱性 を修正したコード(v1.4)に更新いたしました。 […]