PHP Script is not Properly Uploading Images - php

I'm working on a small, user-maintained online store, and am trying to allow my end user (the store administrator) to upload graphics for products. When I run this script, however, it doesn't actually store the image. I built this script from various tips here and a tutorial, and have gotten everything but the image upload portion to work.
// Set the image target directory here
$target = "itemImages/";
$target = $target . basename($_FILES["image"]["name"]);
// Variables get POSTed here - just tack new ones on at the end.
// Various POSTs omitted for brevity
$pic=($_FILES["image"]["name"]);
// Places the picture in the folder
if(move_uploaded_file($_FILES["image"]['tmp_name'], "itemImages/"))
{
echo "The file " . basename($_FILES['uploadedfile']["name"]) . " has been uploaded.<br />";
}else {
echo "There was an issue adding this item. Please try again.<br />";
}
// Writes variables to the database
mysql_query("INSERT INTO tbl_item (itemNAME,itemDESC,itemCOST,itemHCOL,itemHSIZ,itemIMG)
VALUES ('$itemName','$itemDesc','$itemCost','$hasColor','$hasSize','$pic')");
mysql_close($con);
?>
Any help, tips, advice, insight, etc. would be very much appreciated.

move_uploaded_files requires a filename as its target. It does not blindly move to a directory, so
move_uploaded_files($_FILES..., 'somedir/somefile.txt');
works, but
move_uploaded_file($_FILES..., 'somedir/');
will not.
Plus, note that your database operation is vulnerable to SQL injection attacks. You're blindly inserting the uploaded file's remote name (['name'] via $pic), and that name is fully under the remote user's control.

Make sure the itemImages folder has write permission by the user your web server (e.g. Apache) is running as (e.g. www-data)

make sure the .php file and the folder you are writing to have the same "owner". Or try setting permissions on the itemImages folder to 777 (This is not recommended, just a debug tactic)

Related

Security for Flat File CMS (PAAS)

I am building a flat file cms that uses php files. Users will be able to rename files using an input field and the old and new file paths will be sent via ajax to the server where I test for security. I realize this could be done easier with regex or even OR operators. I took the OR operators out so that the strings would not be too long for this post. And as for regex, I'd like more control over the errors I send back to the client.
The CMS itself is much like a PAAS that resides in directory above all of the individual site folders that each user will have. My goal is to keep users from injecting code that might interfere with other (adjacent) user folders or the cms itself in the parent directory above.
I have not parsed the path's yet for validity. I am just trying to get an idea of how a malicious user might be able to take advantage of what I have written so far.
<?php
$old_path = $_POST['file'].'.php'; // path/to/file.php
$new_path = $_POST['new_file'].'.php'; // path/to/newfile.php';
if(strstr($new_path,"<?")){
echo "Sorry, path cannot contain script tags";
}elseif(strstr($new_path,"?>")){
echo "Sorry, path cannot contain script tags";
}elseif (strstr($new_path,">")){
echo "Sorry, path cannot contain script tags";
}elseif (strstr($new_path,"<")){
echo "Sorry, path cannot contain script tags";
}elseif($new_path[0]==="." OR $new_path[0]==='/' OR $new_path[0]==='\\'){
echo 'Sorry first character of path cannot be a period or slash';
}else{
//this is set when the user logs in based on details in a database
$users_dedicated_directory = $_SESSION['userfolder'].'/';
// add the users folder when renaming just for more control
$old_path = $users_dedicated_directory.$old_path;
// add the users folder when renaming just for more control
$new_path = $users_dedicated_directory.$old_path;
rename($old_path,$new_path);
//trim the users folder name. Send it back to the client
echo explode($users_dedicated_directory,$new_path);
}
?>
if new_path is something like a/../../path/to/one/of/you/cms/core/file.php if think a malicious user could overwrite some files of your CMS.
You'll have to remove write permissions for the web server to nay of your CMS files to prevent that.

PHP letting the code add the uploader's last name to the image file he is uploading from a form

Got the server, got the domain, got the code, getting the images successfully, making the products for the customers from the image files they upload. Yay!
Problem: all my image names are image_0001 etc.
Customers can't rename image files from iPhones and do not care to from PCs.
So I was thinking about putting a short form on the upload page asking for customer's last name and having the PHP code attach that name to the image file(s) being uploaded.
If it's not possible, I'm sorry for the inconvenience.
You can rename files after they have been saved to your server, check out the PHP manual for the rename function - http://www.php.net/manual/en/function.rename.php, or just while you are moving them from the tmp directory, you can specify a different name for the uploaded file. See http://www.php.net/manual/en/function.move-uploaded-file.php
Be careful to include something in your code for dealing with naming conflicts.
This one might help :
$imagename = basename($_FILES['file']['name']);
$ext = pathinfo($imagename , PATHINFO_EXTENSION); //we want to change the file name but not the extension
$newImagename= $imageName.$username.'.'.$ext; //assuming you hold the username in $username
if (move_uploaded_file($_FILES['file']['tmp_name'], "/path/{$newImagename}"))
{
....
}

Preventing users from abusing an image deletion script

Basically the following for the core part:
$file = basename($_GET['f']);
$directory = "/var/www/site/";
$file = $directory . $file;
$hash = $_GET['h'];
$md5check = md5($file);
$md5check = substr($md5check, 0, 5);
if ($md5check == $hash) {
if (file_exists($file)) {
unlink($file);
}
else {
die('error');
}
}
else {
header('Location: error');
exit;
}
I realise using the users input is asking for trouble, but how can I get the server to 'locate' the file to delete? Am I somehow able to escape injections?
The user would be loading http://site.com/?f=test.jpg&h=hashc
Also is there any other hash systems besides MD5 which is separate for each location of a file?
eg.
file1.rar downloaded at 12:00am = differenthash
file1.rar downloaded at 11:00pm = randomhash
file1.rar is the same file in both scenarios.
versus md5:
file1.rar downloaded at 12:00am = randomhash
file1.rar downloaded at 11:00pm = randomhash
file1.rar is the same file in both scenarios.
You're already using basename which should limit the attack vector greatly (as the user can't delete files from a different directory), however letting the user have access to delete files from /var/ is a very bad idea as the user would be able to pass any non-image file across too.
Can you not have some path relative to your web root rather than a very important system directory?
Extra security could include (note that this list is not at all exhaustive..):
User checking: Check that the web server user owns the file the user is requesting to delete.
Store uploaded files in the database and check that they exist and have been uploaded by our script before allowing deletion.
As above, move the files out of the system directory.
Use stronger hashing (ie. salts!).
Restrict this to a logged in user and log all actions, if somebody tries to delete a file it's logged and you know exactly who it was.
As #rudi_visser said, best way is white-listing, And store the uploaded files+data in the database.
And when the user tries to delete the file, make sure it's him, and make sure the file is uploaded (exists in the "uploaded" table not a part of your script/system).

Uploaded photo results in "500 Internal Server Error" - PHP/IIS7/Windows Server 2008

I recently moved a website that was written for a LAMP environment to Windows Server 2008. I've managed to get just about everything working now, but I've got one last problem that I can't seem to solve.
I am letting the admin user upload a photo that will get resized to a large file and small file by the PHP script. Both files are getting uploaded perfectly but the large file won't display and will result in a "500 internal server error" when viewed?
I can log onto the server and open both the small and large file, but only the small file is showing on the website? I've copied the PHP script below but the permissions on both files seem to be the same.
I'm using PHP, IIS7 and Windows Server 2008. Hope someone can help,
Steven.
// only process if the first image has been found
if(isset($image_file)) {
// get photo attributes
$image_filename = $image_file['name'];
$image_temp = $image_file['tmp_name'];
$image_ext = substr($image_filename,strpos($image_filename,'.'),strlen($image_filename)-1);
// validate photo attributes
if(strtolower($image_ext) == '.jpg' && filesize($image_temp) <= 4194304) {
// create custom timestamp
$image_timestamp = date('dmYHis');
// clean up filename
$image_filename = trim(str_replace('\'','',$image_filename));
$image_filename = str_replace('\\','',$image_filename);
$image_filename = str_replace('&','',$image_filename);
$image_filename = str_replace(' ','-',$image_filename);
// set file names
$image_large_file = strtolower($image_timestamp . '-large-1-' . $image_filename);
$image_small_file = strtolower($image_timestamp . '-thumb-1-' . $image_filename);
// image url source
$image_source = $_SERVER['DOCUMENT_ROOT'] . '/images/';
// upload image file
if(move_uploaded_file($image_temp,$image_source . $image_large_file)) {
// resize, save & destroy LARGE image
list($image_width,$image_height) = getimagesize($image_source . $image_large_file);
$image_container = imagecreatetruecolor(420,315);
$image_temp = imagecreatefromjpeg($image_source . $image_large_file);
imagecopyresampled($image_container,$image_temp,0,0,0,0,420,315,$image_width,$image_height);
imagejpeg($image_container,$image_source . $image_large_file,75);
imagedestroy($image_container);
// resize, save & destroy SMALL image
list($image_width,$image_height) = getimagesize($image_source . $image_large_file);
$image_container = imagecreatetruecolor(90,68);
$image_temp = imagecreatefromjpeg($image_source . $image_large_file);
imagecopyresampled($image_container,$image_temp,0,0,0,0,90,68,$image_width,$image_height);
imagejpeg($image_container,$image_source . $image_small_file,100);
imagedestroy($image_container);
}
else
$status = '<h3 class="red">Sorry, but there was a problem uploading one of the images to the server</h3>';
}
else
$status = '<h3 class="red">Please check that all the image size\'s are less than 4MB and they\'re all in JPG format</h3>';
}
I know this questions was asked 4 years ago, but I just ran into this same problem, and thought I'd leave an answer for anyone who may come here later.
I found an answer here, but the basic premise is to modify the permissions of the temp folder that PHP initially uploads into. Allowing the IUSR account read access to the temp folder will allow them to view the file when it hits its final destination. Supposedly IIS7 will grant the permissions from the temp folder to the temporary upload file, which, when moved to your website directory, will keep those temp folder permissions.
Security-wise, you are allowing read access to your temp folder; so if you have sensitive information that ends up there at any point, you may have to find another solution.
A little more information can be found here
I got stuck into the same problem and i think this will help somebody
Right-Click uploads directory / folder and select ‘Properties’
Go to ‘Security’ tab
Click Edit
Select ‘IUSR’ under group or user names
Select ‘Read & Execute’ under permissions for IUSR
Click ‘Apply’ and ‘Ok’
Found this on http://wingedpost.org/2016/07/preventing-500-internal-server-error-uploaded-files-iis-php-sites/

PHP and mysql question

hello everyone i'm having some problem ... question is i want to get the information from a form and save it in database the data is (comment, uploading pictures and email) when i did it it gave a warning
the code
// move file from temp location on server to your uploads folder
move_uploaded_file($F1["tmp_name"], "Uploads/$F1[name]");
print "Stored in: Uploads/$F1[name]";
// save location of upload to text file uploads.txt for later use
$datafile = fopen("uploads.txt","a");
flock($datafile,1);
fwrite($datafile, "Uploads/$F1[name]\n");
flock($datafile,3);
fclose($datafile);
// divide size by 1024 to get it in KB
/* if ($F1["size"] / 1024 > 50) {
print "Your gif file is too large! Less that 50KB please!";
exit(0);
}*/
if (!(IsSet($_FILE["fname"]))) {
$query="insert into guestbook (comments, email, img,display) values
('$_POST[comments]','$_POST[email]','some address ', '0')";}
else
$query="insert into guestbook (comments, email, img, display) values
('$_POST[comments]','$_POST[email]','some addres', '$_POST[0]')";
the warning i got is
Warning: move_uploaded_file(Uploads/holder.jpg): failed to open stream: No such file or directory in (address) on line 48
Warning: move_uploaded_file(): Unable to move '/tmp/php4OAZMC' to 'Uploads/holder.jpg' in (some address) on line 48
Stored in: Uploads/holder.jpg
how can i fix it ?
thanks in advance
I think it needs an absolute path for the file to be saved to, not a relative to the script location, i.e.
/home/meme/www/example.com/Uploads/
Also, check your permissions for the Upload directory. Also another little tip that'll save your bacon in the future- keep directory and filenames in lower case; then you won't get bitten in the bottom sometime in the future when your code is looking for a file or directory that doesn't exist because your filesystem is case sensitive!
Does the Uploads/ folder already exist? If not, trying creating it first. That might be causing the error.
Also, its a good idea to check if move_uploaded_file() worked or not. It returns true if it worked, and false if not.
Also, as already mentioned, try using an absolute path as well.
Reference
You should also ensure that your Uploads folder has it's permissions set correctly - For testing purposes, chmod the Uploads folder to 777 using your favourite FTP client.
Make sure that when you're ready to put your upload into practice you ensure you secure the folder properly (ensure not just anyone can write to it) and make sure you put filters in place for the file types.
Check to insure the path to move to exists, and your webserver process has rights to write to it.
Your insert query is a gaping security hole just waiting for a SQL injection. You can use the following to reduce the likelihood of getting hacked:
$comments = mysql_real_escape_string($_POST['comments']);
$email = mysql_real_escape_string($_POST['email']);
$query="insert into guestbook (comments, email, img, display) values
('{$comments}','{$email}','some address ', '0')";

Categories