質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.77%

画像アプロードにおけるセキュリティ対策が、なぜ大変なのかわかりません。

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 5
  • VIEW 1,252

kikijiji

score 3

前提・実現したいこと

画像アップロード機能を実装しています。調べているとセキュリティ周りを組むのが大変そうで腰が引けたのですが、ふと次の方法でいいのではないかと思いました。問題やセキュリティリスクがないか知りたいです。

考えた方法

■保存フロー

  1. JSで画像をbase64にし、
  2. AJAXで送り、
  3. 送られたbase64のテキストについて以下検証し
    ➀タグがあるか?
    ➁画像かどうか?
  4. base64のテキストのままデータベースに保存する

■表示フロー

  1. データベースにあるbase64のテキストを取得
  2. htmlspecialchars()をかけて出力

ソースコード

上の流れなら、通常のコメントを受け付けるのと同じ検証でいいですよね?

ただのテキストの検証なので、唯一やるべき検証である3の➀と➁は、次のコードで済むと思います。

そのように思ったのですが、base64のテキストで送るこの方法には、何か問題あるのでしょうか?

<?php
// AJAXでbase64化された画像を受け取る
$base64 = $_POST['base64'] ?? ''; // "data:image/jpeg;base64,/9j/ABCDEFG" など

// ➀と➁が問題あれば終了
if( isHtml($base64) || ! isImg($base64) ) {
  echo '問題が発生しました';
}else{
  $sql = "INSERT INTO images (ID, base64, created) VALUES (:base64, now())";
  $stmt = $dbh->prepare($sql);
  $params = array(':base64' => $base64);
  $stmt->execute($params);
  echo '登録完了しました';
}

// ➀タグがあるか?
function isHtml( $base64 ) {
  $result = false;
  if ( preg_match("/<(\"[^\"]*\"|'[^']*'|[^'\">])*>/", $base64) ) $result = true;
  return $result;
}

// ➁画像かどうか?
function isImg( $v ){
  $result = false;
  if ( preg_match("#^data:image/jpeg;base64#", $v) ) $result = true;
  if ( preg_match("#^data:image/jpg;base64#", $v) ) $result = true;
  if ( preg_match("#^data:image/png;base64#", $v) ) $result = true;
  return $result;
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • m.ts10806

    2020/06/08 16:46

    なにか問題があるような点はどこからきた懸念点でしょうか。出典明示してください

    キャンセル

  • kikijiji

    2020/06/08 16:54

    ざっくり言いますと「こんな簡単な方法がネットに載ってないということは、何か問題があるのだろうか?」という懸念です。

    キャンセル

  • Lhankor_Mhy

    2020/06/08 17:51

    data:image/jpeg;base64" onclick=alert()
    という文字列がチェック通るからあまり意味がないような……?

    もちろん、出力時の htmlspecialchars で潰せますが、それに頼るなら①の入力時サニタイズする意味はあまりないのではないかな、と。
    ②は必要だと思いますが。

    キャンセル

  • kikijiji

    2020/06/08 18:06

    なるほど画像チェックはこれではいけませんね。もう少し調べてみます。

    キャンセル

回答 3

checkベストアンサー

+6

// ➁画像かどうか?

このチェックでは不適切なものを弾ききれません。data:で送ってくるContent-typeはクライアント側が設定するものですので、攻撃者が送信する場合はいくらでも詐称可能です。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/06/08 17:31

    それこそ「精神的ブラクラ」(コンピューターのシステム上は至って正常なファイルだけど、見る人間の精神にダメージを与えるような画像)なんてものもありますので、完璧というのは困難です。

    キャンセル

  • 2020/06/08 18:07

    ありがとうございます。画像チェックはもっと考えないといけないですね。

    キャンセル

+4

既に解決されたようですが、追加で。
この手の方法は使われてなくもないようですが、あまり見かけない理由の一つは、ブラウザおよびサーバーり両方で画像がメモリ上で処理されるので、あまり大きな画像(または他のアップロードデータ)は使いにくいというのがあると思います。$_FILESだと、アップロードデータはファイルとして扱われ、それがセキュリティ上の問題を生みやすい原因の一つになっています。

小さな画像であれば、base64でデータサイスが1.3倍程度になるオーバーヘッドを除けば、あまり問題にはならないかと。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/06/09 09:11

    ありがとうございます。base64の方のそういった事情を知りたかったです。確かにLazyLoadなどができなそうですね。

    ファイルの方ですが以下に便利なライブラリがございまして、こちらネットに問題点もなかったようですが、専門家の方からしますとこういったライブラリはいかがでしょうか。
    使い方参考サイトにあるように「$handle = new Upload($_FILES['image_file']);」だけでセキュリティをばっちりチェックしてくれるようです。

    「class.upload.php」
    (使い方参考サイト)
    http://webtech-walker.com/archive/2007/06/11210929.html
    (Github)
    https://github.com/verot/class.upload.php/blob/master/src/class.upload.php

    キャンセル

  • 2020/06/09 09:13

    そういった既存のライブラリのセキュリティチェックはお仕事なので、こちらでの回答は控えたいと思います

    キャンセル

  • 2020/06/09 16:36

    そうですよね、専門家なら簡単かと思いましたが、専門家だからこそ安易な回答をしてはいけませんでしたね。大変失礼いたしました。YouTubeの方で期待しています(笑)

    キャンセル

+1

普通にファイルをsubmitして、ファイルはファイルとして保持しておけば
大した手間ではありません。
ただimgで参照されたときになんらかの不正な動きをする可能性は否定できません。
(その昔そういう攻撃があった)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/06/08 17:13

    たとえばその「普通にやる」というのは、具体的にはどういった流れでしょうか?こちら(https://qiita.com/ichimura/items/0c4e5d2dd6fe8b55018e)ではかなり大変な検証がされていますが、これらの検証がある程度省略できるような方法なのですか?

    キャンセル

  • 2020/06/08 17:16

    逆にbase64だなんだはどうでもいいです。
    ポイントは受け取ったファイルをシステムが参照したり
    ユーザーのブラウザ上で表示したときに致命的なセキュリティ問題を
    起こすか否かだけ気にしてください。

    たとえばウィルスやトロイの木馬だってファイルのアップロード時には
    紛れ込む可能性はあるわけです

    キャンセル

  • 2020/06/08 18:19

    画像が大変=なぜ画像じゃなければ(画像と比べると)簡単なの?と逆の考え方した方がスッと思いつきやすいような。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.77%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る