安全なアップロードスクリプト

Aug 17 2020

ユーザーがプロフィール写真をアップロードできるソーシャルネットワークを作成しています。これが安全な方法かどうかを知りたいだけです。ありがとう。

<?php

include 'includes/header.php';
include 'includes/form_handlers/settings_handler.php';

//$userPic = ''; $date_time = date('Y-m-d_H-i-s');

if(!empty($userLoggedIn)) { if (isset($_FILES['fileToUpload'])) {
        $errors= array(); $file_name = $_FILES['fileToUpload']['name']; $file_size = $_FILES['fileToUpload']['size']; $width = 1500;
        $height = 1500; $file_tmp = $_FILES['fileToUpload']['tmp_name']; $file_type = $_FILES['fileToUpload']['type']; $tmp = explode('.',$_FILES['fileToUpload']['name']); $file_ext=strtolower (end ($tmp)); $extensions = array( "jpeg", "jpg", "png", "gif");

        if(in_array($file_ext,$extensions)=== false){

            $errors[]="extension not allowed, please choose a JPEG or PNG file."; } if ($file_size > 8097152) {

            $errors[] = 'File size must be 2 MB'; } if ($width > 1500 || $height > 1500) { echo"File is to large"; } if(!$errors) {

            $userPic = md5($_FILES["fileToUpload"]["name"]) . $date_time . " " . $file_name;
            $profilePic = move_uploaded_file($file_tmp,"assets/images/profile_pics/" . $userPic); $file_path = "assets/images/profile_pics/" . $userPic; $stmt = $con->prepare("UPDATE users SET profile_pic = ? WHERE username = ?"); $stmt->bind_param('ss', $file_path, $username);
            $stmt->execute(); $stmt->close();

            header('Location: settings.php');
            exit();
 
        }
    }
} else {

    echo "Invalid Username";
}

?>

回答

5 LiamSorsby Aug 18 2020 at 21:13

これは私の個人的な意見ですが、私は次のように言います:

  1. コードはフォーマットする必要があります。可能な場合はこの標準に従う必要があるため、私は個人的にPSR-12を検討します。
  2. move_uploaded_fileは、ディレクトリトラバーサルから保護しません。ベース名$_FILES['fileToUpload']['tmp_name']と他のいくつかの形式の検証を使用する必要があります
  3. でファイル拡張子をチェックしif(in_array($file_ext,$extensions)=== false)ても、ユーザーが悪意のあるファイルをアップロードするのを防ぐことはできません。たとえば、マジックバイトを使用して、サーバーをだまして特定の種類のファイルであると思わせることができます。finfoとファイルアップロードの最初の例を見てください。
  4. エラーの配列を作成しています。現在、これはifステートメントでチェックされており、破棄されます。使用する予定がない場合は、実行を継続するよりも、関数を早期に終了する方がよい場合があります。
  5. ファイル名の一意性に応じて、次のようなものを使用することをお勧めします uniqid(mt_rand(), true)
  6. move_uploaded_fileは、ファイルがすでに存在する場合はそれを置き換えます。既存のファイルを上書きする前に、これが存在することを確認することをお勧めします。ネーミングソリューションによっては、発生する可能性は非常に低いですが、高負荷で長期間使用すると、予想よりも頻繁に発生する可能性があります。
  7. 使用UPDATE users SET profile_pic = ? WHERE username = ?しているのは、ユーザーがログインする必要があるため、この値がデータベースに存在すると想定します。ただし、フィールドが存在するかどうかわからない場合(データベースを見たことがない)、個人的に使用する:INSERT INTO users (profile_pic, username) VALUES (?,?) ON DUPLICATE KEY UPDATE profile_pic=?, username=?行が存在しない場合はテーブルに挿入されますが、存在する場合は更新されます。
  8. widthとheightというローカル変数を設定し、それらを同じ値と比較しています。これは実際のファイルのサイズを確認するためのものだと思いますか?

これが何らかの形で役立つことを願っています:)