読者です 読者をやめる 読者になる 読者になる

FileAPIを使って画像をアップする際はバイナリチェックも

JS

FileAPIを使って画像をアップする際は、ファイルの拡張子を偽装してもアップできるので、バイナリチェックを行うほうがよりしっかりします。
JPEG画像をFileAPIを使ってアップすると、下記のようなbase64文字列を取得することができます。

data:image/jpeg;base64,/9j/4AAQSkZJRgABA....

画像ファイルの先頭バイトには、拡張子を判断するフラグが挿入されており、この/9j/JPEGを表す文字列となります。

画像タイプ バイナリ base64
jpeg a a
png a a
gif a a
アニメーションgif a a

作成中・・・
PHP側で生データーを取得した際は、このヘッダーを見て画像形式を判断します。
そこで、ためしに、拡張子JPEGと偽装した、ZIPファイルをFileAPIで上げてみたところ、

data:image/jpeg;base64,{ZIPファイルをbase64でエンコードしたもの}

となり、ブラウザはdata:image/jpegで扱おうとします。
base64には使用できる文字が限られているため、XSSなどはできませんが、思わぬトラブルが起きる可能性がありますので、バイナリチェックも入れておくと、余計なファイルがアップされなくて済みます。

サンプルソースはこちら

<!DOCTYPE html>
<html>
<head>
  <title></title>
  <input type="file" id="files" name="files[]" multiple />
  <script>
    function doFileSelect(evt) {
      var files = evt.target.files;
      for (var i = 0, file; file = files[i]; i++) {
        if (!file.type.match('image.*')) {
          continue;
        }
        var freader = new FileReader();
        freader.onload = (function(theFile) {
          return function(e) {
            if( ( e.target.result ).substr(5,10) == "image/jpeg" ){
              if( ( e.target.result ).substr(23,4) == "/9j/" ){
                alert("This is JPEG file !! ");
              }
            }
          };
        })(file);
        freader.readAsDataURL(file);
      }
    }
    document.getElementById('files').addEventListener('change', doFileSelect, false);
  </script>
</head>
<body>
</body>
</html>