Is the way i am handling image uploads secure? Is there ANY way someone could upload a .php file, or some other file which can somehow execute php code (even if the attacker would know the actual file path after the upload?)
function random($longueur = 10)
{
return substr(str_shuffle(str_repeat($x='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil($longueur/strlen($x)) )),1,$longueur);
}
$random = random(5);
//POST DATA
$img_name = htmlspecialchars($_POST["img_name"]);
//IMAGE
mkdir('../../assets/images/'.$random.'/');
$target_dir = '../../assets/images/'.$random.'/';
$target_file = $target_dir . basename($_FILES["img_src"]["name"]);
$imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION));
//ARRAY EXTENSION GOOD
$extension_autorisee = array('.png', '.jpg', '.jpeg', 'png', 'jpg', 'jpeg');
if (in_array($imageFileType, $extension_autorisee)){
//MOVE IMAGE
move_uploaded_file($_FILES["img_src"]["tmp_name"], $target_file);
$filename = $random."/".$_FILES['img_src']['name'];
}
It appears reasonably secure, the only thing is that it doesn't check MIME types. I don't really know for what purpose you are storing these files and most modern browsers will just throw an error when they receive an image with HTML embedded in it, but it's still something to look into.
Also I'm not an expert in cryptography but you might want to look into the "randomness" of that string. This might be a good resource. Cryptographically Secure Random String Function
Apart from that it looks fine.
Lightning edit: This kind of questions are, I think, more suited for https://codereview.stackexchange.com/
Related
I have written a php script which checks the image file for its extension, such as JPG, JPEG, PNG, GIF, uploaded through an HTML form.
Now comes my problem: anyone may upload any kind of file by giving it an extension of JPG, JPEG, PNG, GIF.
Can someone help me on that? One should strictly be able to upload only an image file and not any other file which carries just extension of Image file.
I tried hard... but failed... Here is the php script I have written
CHECK MY FULL CODE I HAVE WRITTEN & ITS WORKING FINE BUT WHEN I CHANGE ANY FILE EXTENSION WITH IMAGE EXTENSION ITS ALLOWING UPLOAD ON SERVER WHICH IS NOT SERCURE PLEASE SEE THIS FULL CODE AND ADD SOLUTION , THIS WILL HELP OTHERS TOO -THANK YOU https://www.dropbox.com/s/prza75dyo7usjqy/secure%20image%20upload%20with%20checking%20extension.txt?dl=0
if (isset($_POST['submit']))
$filename = $_FILES["file"]["name"];
$file_basename = substr($filename, 0, strripos($filename, '.')); // get file extention
$file_ext = substr($filename, strripos($filename, '.')); // get file name
$filesize = $_FILES["file"]["size"];
$allowed_file_types = array('.jpg','.png','.jpeg','.gif');
//instead of allowed file type i want to check image authenticity with MIME
if (in_array($file_ext,$allowed_file_types) && ($filesize < 100000))
You should use the fileinfo API, which makes you able to check a file MIME content-type by looking at its bytes, not its name.
An image MIME type always starts with image/, for example image/png.
$finfo = new finfo();
$mimeType = $finfo->file($_FILES['file']['tmp_name'], FILEINFO_MIME_TYPE);
$isImage = strpos($mimeType, 'image/') === 0;
If you want to be very restrictive on your allowed images, check the list of available MIME types.
Edit: be more specific
if (isset($_POST['submit'])) {
$filename = $_FILES["file"]["tmp_name"];
$filesize = $_FILES["file"]["size"];
$allowed_file_types = array('image/jpeg','image/png','image/gif');
$finfo = new finfo();
$mimeType = $finfo->file($filename, FILEINFO_MIME_TYPE);
$isImage = in_array($mimeType, $allowed_file_types);
if ($isImage && $filesize < 100000) {
The most secure way to check if something is really an image, is to open the file as an image and then re-generate it.
Things that are valid images can still carry loads of other information and sometimes can trick whatever is reading it. So the most safe thing is to take the pixels from the image, and regenerate it.
Extensions like fileinfo only check the first few bytes for a marker, but it's not 100% reliable. It might be good enough for you
I would like to have a check whether an uploaded file sent via email and not saved in the DB, allow only the following extensions.
Is this something secure?
$allowed = array('pdf','doc');
$filename = $_FILES['video_file']['name'];
$ext = pathinfo($filename, PATHINFO_EXTENSION);
if(!in_array($ext,$allowed) ) {
echo 'error';
}
No it isn't (a file could have two extensions : image.php.jpg).
If you are planning to upload only images, one good thing is to try to get image size with getimagesize and remove it from temp folder if it returns false
If this is a newby question, forgive me. I have coded a php file uploader. After hearing that hackers could attatch/disguise code to images to infect sites, I got an idea to solve that problem. To convert the upload image to another file format (png) and then to another (jpg) with 70% quality. This caused the malware to become corrupted. The problem is, this total conversion process takes a about 1 minute at top speed. The service I'm making needs to be quick to handle the file uploads so that the users can go about the work. How can I speed up this process? The upload code is below (important variables are blanked).
// upload the file
$status = "...recieving the file...";
move_uploaded_file($_FILES["file"]["tmp_name"], "$folder" . $_FILES["file"]["name"]);
$status = "...processing the file...";
// convert the file to destroy viruses
$filename21 = "$folder" . $_FILES["file"]["name"];
imagepng(imagecreatefromstring(file_get_contents($filename21)), "$folder"."debug.".$picture_newname.".png");
$imageTmp=imagecreatefrompng("$folder"."debug.".$picture_newname.".png");
imagejpeg($imageTmp, "$folder".$picture_newname.".jpg", 90);
imagedestroy($imageTmp);
These are the steps it follows:
Scan database for file with the same name
if file with same name is found, rename the current upload
receive the file
"evaluate" the file (the double conversion process to protect the server)
insert the info into the uploads database
If any other codes are needed (or if i should do some more timing) please let me know. Thanks in advance for your assistance.
This is a crazy idea. You're not just tying up the server in converting between image formats, you're also degrading the quality of every uploaded image.
I'd recommend a different approach
When a file is uploaded, use PHP's getimagesize() function to check the image. If this function returns FALSE (or an unexpected image type, or strange dimensions, etc.), then the file is corrupt and can be deleted.
Use exiftool or something similar to strip away all the metadata from the uploaded file before you store it away on the server. That way you can ensure that the file only contains image data.
Perhaps you could check that the value of $_FILES["file"]["name"] doesn't contain anything sneaky like ../../ before you use it to save the file on your server.
It's totally bad idea implement double conversion for security purpose, because of DoS attack.
Balanced solution between speed & security must contain:
Check MIME type.
Check file extension.
Check file size. (highly recommended)
Check image size. (optional, depends on application requirements)
Something like this:
$allowable_types = array(
'png' => 'image/png',
'jpeg' => 'image/jpeg',
'gif' => 'image/gif'
);
$max_file_size = 10240; // 10K limit example
$finfo = new finfo(FILEINFO_MIME_TYPE);
$type = $finfo->file($_FILES['name']['tmp_name']);
$size = filesize($_FILES['name']['tmp_name']);
$info = pathinfo($_FILES['name']['tmp_name']);
if (isset($allowable_types[$info['extension']])
and $type === $allowable_types[$info['extension']]
and $size <= $max_file_size
) {
// check image size if your app require this
move_uploaded_file($_FILES['name']['tmp_name'], $destination);
}
Update
I would not recommend to use $_FILES['file']['name'] in destination path or scan whole directory for same name. Because of some security flaws and performance drop. Better solution is to generate unique name for each image:
$new_name = uniquid() . '.' . $info['extension'];
$destination = $upload_path . $new_name;
I've got upload.php file with these file types allowed:
$allowedExtensions = array("mp3","mp4","jpg","jpeg","gif","png");
It performs upload correctly but when uploaded file is larger than 5mb (chunk size is set to 5mb) then it stops working unless I extend my array with BLOB (Javascript console returned this error as response from upload.php - that's how I know what was the problem):
$allowedExtensions = array("mp3","mp4","jpg","jpeg","gif","png","blob");
Can anyone explain me what that BLOB is? It's some kind of upload PART/CHUNK stored on server? Are there any other surprises I should include in allowedExtensions?
My upload.php is the one from Plupload.com: https://github.com/downloads/moxiecode/plupload/plupload_1_5_4.zip (unzip, go to /examples/ and open upload.php). I only extended it by adding this:
foreach($_FILES as $file){
if($file['tmp_name'] > ''){
if(!in_array(end(explode(".", strtolower($file['name']))), $allowedExtensions)){
die($file['name'].' is not an allowed file type!');
}
}
}
BLOB = Binary Large OBject. Its a database field type for storing binary data.
Without starting a war, IMHO pictures do not belong in a database. Store them on disk and keep a reference to them in a database table.
foreach($_FILES as $file){
if(isset($file['tmp_name']) && $file['tmp_name'] != ''){ <--- HERE IS THE CHANGE
if(!in_array(end(explode(".", strtolower($file['name']))), $allowedExtensions)){
die($file['name'].' is not an allowed file type!');
}
}
}
I modified your loop to help avoid warnings.
I know this topic is widely talked about. I've done my research, and decided to store image files onto the server instead of the DB as a blob file. The problem that I am having is trying to figure out the best way to upload the file, store it in a designated folder then storing the destination in the db..say../img/something.jpg - I've tried looking through many resources but most of them are missing some important steps in the process.
Problems:
Finding a secure way for uploading the img file
Limiting the file
size Uploading the image to a destination file
Storing the destination file as a text in the DB
I'm using PHP and MySQL.
Dunno what all your points about, but what you really have to be concerned with is
check for the file extension.
extract it from the filename and compare with allowed ones.
also it would be good to check filename to have only one dot, or at least it doesn't have a name like name.html.jpg, due to some odd Apache behavior.
check for the file contents. the best way would be to create a brand new image out of the uploaded one.
take usual precautions while working with DB.
Here you go, this covers the basic ideas of what you want to do:
<?php
$allowedTypes = array("image/jpg", "image/jpeg", "image/png");
$maxSize = 3 * 1024 * 1024; // 3Mb
$fileType = $_FILES["file"]["type"];
$fileSize = $_FILES["file"]["size"];
// check if there was an error
if ($_FILES["file"]["error"] > 0)
{
die($_FILES["file"]["error"]);
}
// check if the filetype is valid
if (!in_array($fileType, $allowedTypes))
{
die("Invalid file type: $fileType");
}
// check if the size doesn't exceed the limitations
if ($fileSize > $maxSize)
{
die("The file was too big: $fileSize");
}
$name = $_FILES["file"]["name"];
$tmpfile = $_FILES["file"]["tmp_name"];
// check if the filename is valid
if (preg_match("/[\w-]+\.(jpg|jpeg|png)$/", $name) != 1)
{
die("Invalid file name: $name");
}
// create unique name if needed
$path = "/var/www/images/" . $name;
move_uploaded_file($tmpfile, $path);
// add the filepath to mysql
mysql_connect("localhost", "username", "password");
mysql_select_db("imagedb");
mysql_query("INSERT INTO images (Location, Size) VALUES ('$path', '$size');");
?>
This is meant to show how it could be done.
read this
personally I'd use imgur which is used here on stackexchange websites