I have a form that a user fills in with lyrics and uploads an album cover. The submitted data will be inserted into the database, and the album cover will be moved to a subfolder.
localhost/project-folder/covers
I took some precautions (escaping, prepared statements) for SQL Injection to enter the form. I recently learned that I also need to take precautions to download a file (image) so that the user can upload malicious images.
For example, adding HTML, JS, or PHP code to image metadata or embedding code directly in an image file . Since I have not often used PHP, I do not understand how this creates a problem, especially in my case.
I am doing server side form validation.
local / project folder / text / add.php
<form action="../scripts/lyrics/submit_lyrics.php" id="lyricsForm" method="post" autocomplete="off" enctype="multipart/form-data">
<i> local / project-folder / scripts / text / submit_lyrics.php
$form_data = new FormData(["artist", "album", "song", "year", "track_no", "lyrics"], "sssiis"); $file_data = new FileUpload("cover", [ "max_file_size" => 512 * 1024, "extensions" => ["gif", "jpg", "jpeg", "png"], "mimes" => ["image/gif", "image/jpeg", "image/png"], "max_width" => 1024, "max_height" => 1024, ]); $cover = new Cover($mysqli, $form_data, $file_data, BASE."covers/");
Validation is performed during the initialization of FormData and FileUpload . If there is an invalid field or the uploaded image is invalid, the user is redirected back to the form page (add.php) with the appropriate warnings.
One way to prevent the download of the malicious image that I read was to create a new image from the downloaded one, and that is exactly what I do inside new Cover() . I also resize the uploaded image to make this approach work. I am doing a resize using this function:
public function new_image($file_data, $new_width, $new_height) { $img_data = file_get_contents($file_data->tmp_name); $image_type = $file_data->type; $img_create = null; switch ($image_type) { case IMAGETYPE_GIF: $img_create = "imagecreatefromgif"; break; case IMAGETYPE_JPEG: $img_create = "imagecreatefromjpeg"; break; case IMAGETYPE_PNG: $img_create = "imagecreatefrompng"; break; } $uploaded_image_resource = $img_create($file_data->tmp_name); $new_image_resource = imagecreatetruecolor($new_width, $new_height); imagecopyresampled($new_image_resource, $uploaded_image_resource, 0, 0, 0, 0, $new_width, $new_height, $file_data->image["width"], $file_data->image["height"]); return $new_image_resource; } public function write_to_disk() { if (isset($this->image["resource"])) { $destination = $this->target_dir . $this->file_name . ".jpg"; imagejpeg($this->image["resource"], $destination); imagedestroy($this->image["resource"]); } }
This resizing also removes (I think) any code in the metadata and / or code embedded in the image (if any) since I am creating a new clean image.
Is this enough to protect file downloads? Did I miss something? Are there other things I need to know about?