FileAPIを使って画像をアップする際はバイナリチェックも
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>