I'm trying to use WordPress on the AppFog PaaS system. Unfortunately, AppFog doesn't have persistent storage so all content outside of the database needs to be stored on some external system (like S3). I'm successfully using a plugin which pushes all my WordPress media out to S3, but am having problems loading some of the images.
To investigate, I deployed the following script:
// get the image name from the query string
// and make sure it's not trying to probe your file system
if (isset($_GET['pic'])) {
$pic = $_GET['pic'];
// get the filename extension
$ext = substr($pic, -3);
// set the MIME type
switch ($ext) {
case 'jpg':
$mime = 'image/jpeg';
break;
case 'gif':
$mime = 'image/gif';
break;
case 'png':
$mime = 'image/png';
break;
default:
$mime = false;
}
// if a valid MIME type exists, display the image
// by sending appropriate headers and streaming the file
if ($mime) {
header('Content-type: '.$mime);
header('Content-length: '.filesize($pic));
$file = fopen($pic, 'rb');
if ($file) {
fpassthru($file);
exit;
}
}
}
?>
Which allows me to directly test my ability to read and write an image in PHP. This proxy script works perfectly for images under around 10KB -- i.e. when I open the script in a browser pointing it at some "small" image file in my S3 bucket, I'm able to see it.
However, when I attempt to load a "large" file (anything over 10KB), I get an error. In Firefox, that's:
The image “http://myssite.com/iproxy.php?pic=http://aws.amazon.com%2Fmybucket%2Fwp-content%2Fuploads%2F2013%2F01%2Fmylargeimage.png” cannot be displayed because it contains errors.
I've been wrestling with this for hours and can't seem to figure anything out. I've tried changing the output_buffering to a larger value but that hasn't helped.
Any tips would be appreciated!
Related
I'm using PHP IMAGE MAGICIAN for resizing the images of my website.
When I try to resize the image with a changed extension (e.g. changing image.jpg to image.gif), the function returns an error because the image is invalid in this situation. I want to avoid this error.
I tried a lot of methods to check is the image valid but without success.
The error which appear is:
"file
/Users/.../uploads/1541963916_4dd672e5f3a3060ced41f3f7975453c9.gif is
missing or invalid"
Every image I upload to my website I am renaming to a new filename with its extension.
This is the part of code which I am using.
$workWithImage = new imageLib(UPLOADS_DIR . $original);
$workWithImage->resizeImage($width, $height, $type);
$workWithImage->saveImage(UPLOADS_DIR . $thumbnail, $imageQuality);
I searched for this problem but I could not find a solution.
Unfortunately looking at source this library seems to not handle this situation at all. You can create bug report at library home page. What you can do is compare mime type of file with it's extension and either do you own error handling or rename file name to have correct extension. Mime type detection code used by this library is
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_file($finfo, $file);
finfo_close($finfo);
switch($mimeType) {
case 'image/jpeg':
case 'image/gif':
case 'image/png':
case 'image/bmp':
case 'image/x-windows-bmp':
$isImage = true;
break;
default:
$isImage = false;
}
Your File Path is not valid.
You have a path error like : "/Users/.../uploads/1541963916_4dd672e5f3a3060ced41f3f7975453c9.gif"
After /Users/ you have stille three dots "..." that is not passible .. dots for a folder backwards. And one dot . for root direcotory.
Your Errocode, says: "file /Users/.../uploads/1541963916_4dd672e5f3a3060ced41f3f7975453c9.gif is missing or invalid"
Ist Invalid PATH, that means he cant find your file in your system.
this is my download.php;
session_start();
$file = $_GET['file'];
download_file($file);
function download_file( $fullPath ){
// Must be fresh start
if( headers_sent() )
die('Headers Sent');
// Required for some browsers
if(ini_get('zlib.output_compression'))
ini_set('zlib.output_compression', 'Off');
// File Exists?
if( file_exists($fullPath) ){
// Parse Info / Get Extension
$fsize = filesize($fullPath);
$path_parts = pathinfo($fullPath);
$ext = strtolower($path_parts["extension"]);
// Determine Content Type
switch ($ext) {
case "pdf": $ctype="application/pdf"; break;
case "exe": $ctype="application/octet-stream"; break;
case "zip": $ctype="application/zip"; break;
case "doc": $ctype="application/msword"; break;
case "xls": $ctype="application/vnd.ms-excel"; break;
case "ppt": $ctype="application/vnd.ms-powerpoint"; break;
case "gif": $ctype="image/gif"; break;
case "png": $ctype="image/png"; break;
case "jpeg":
case "jpg": $ctype="image/jpg"; break;
default: $ctype="application/force-download";
}
header("Pragma: public"); // required
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false); // required for certain browsers
header("Content-Type: $ctype");
header("Content-Disposition: attachment; filename=\"".$_REQUEST["isim"]."\";" );
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".$fsize);
ob_clean();
flush();
readfile( $fullPath );
} else
die('File Not Found');
}
This is forced jpg download file. But this file can download all .php files.
Normaly i use this download link and download image;
http://domain.net/download.php?file=wp-content/uploads/2016/04/10/126379-fantasy_art.jpg
But then i tested this link download my config file...
http://domain.net/download.php?file=wp-config.php
I think this is big vulnerable.
How can i fix this? i dont want download any .php files...
Thanks..
Use default in your switch case to avoid this problem:
Remove this:
default: $ctype="application/force-download";
For this: default: die('File not found'); or default: return false;
Also you could check if path makes sense, like it should be a subfolder of uploads. This post has some info for you: Test if a directory is a sub directory of another folder
I think it would be good for you to step back and consider what this script actually does, because it is still a gigantic security hole. Here is what it does:
Take the user's input (which is always untrustworthy)
See if it's extension is allowed according to a small list of possible extensions
If so, pass it off to the user
Now that you have it die for unrecognized file extensions, it won't let them download your actual php files. But it will still let the user do all sorts of terrible things, all of which comes down to one very key issue:
You make no attempt to verify that the file being requested is actually reasonable for the person to view!!!
A key point is that readfile() doesn't care where the file is. Nor does it even assume that the file is in your website's public directory. The only reason it is downloading files from your web directory is because you didn't start the filename with a slash. However, readfile() will happily pass along anything on the server that it has read access to. Without your recent change a user could have just as easily done this:
http://domain.net/download.php?file=/etc/passwd
Moreover, it doesn't even have to be an actual file on the server. In most PHP installations PHP will happily load up URLs as actual files. So someone could also use your script as a proxy:
http://domain.net/download.php?file=http://theFBIwillArrestYouIfYouLoadThis.com/secrets.pdf
That sort of vulnerability (the ability to use your script as a proxy) is still present in your current solution. Anytime I see a website take file paths like this I love to see just how much it will let me get away with. You could set yourself up for a world of hurt in the worst case scenario.
You have to look at it from a defense-in-depth scenario. What it boils down to is the difference between blacklisting (what is the user not allowed to do) and whitelisting (what should this user be allowed to do). Good security practices rely on the latter method of thinking exclusively, because it is impossible to come up with a completely exhaustive blacklist that covers all possible scenarios.
In a case like this if you want a user to be able to download files you need some sort of list of files that are allowed to be downloaded. One example would be to place any file that is supposed to be downloaded into a specific directory. If a user requests a file then your script can use realpath() to make sure that file is actually in your public directory and otherwise forbid the download. Although if they are all in one directory you could just as easy change a configuration rule in your webserver (e.g. apache or nginx) to have it automatically add the 'content-disposition: attachment' header to anything in that directory. Then you just have to make sure that you never put the wrong files in that public directory.
Me personally though, I would approach it with a complete white-list. I would never let someone specify a filename and then use it to download a file. Rather I would have an administrative area where I manage files that are marked for download: the list of allowed files would be stored in the database and managed by me. When the user downloads a file they don't do it by specifying a filename but rather by specifying the id from the database that corresponds to the file they want to download (a simple user interface is necessary to facilitate this). The ID is used to lookup the file path, and the file can then be downloaded safely. You can then even store the files in directories outside the public area of your website so that you have full control over who can access the files.
That last suggestion is probably overkill for what you are trying to do, but the short of this is simple: you have to think carefully about the security implications of your code and make sure you are giving the user the minimum amount of privileges possible.
I'm having a stump with some PHP...
I have a Flash Application that sends an image (using as3corelib) to a PHP script that previews it in the browser, which works! But, I would actually like it to permanently save it the a server folder (uploads, etc.) instead of temporarily saving it. I can't find the right variable in the PHP that actually sends the image to a server so it could save it.
<?php
switch ($_POST["format"]) {
case 'jpg':
header('Content-Type: image/jpeg');
break;
case 'png':
header('Content-Type: image/png');
break;
}
if ($_POST['action'] == 'prompt') {
header("Content-Disposition: attachment; filename=" . $_POST['fileName']);
}
echo base64_decode($_POST["image"]);
?>
Here's an example of it: http://shmoggo.com/snapshot
JPEG, Open to Browser (but I would like it to SAVE to browser)
Any PHP guru help would be terrific, thanks a lot!
Aaron
If you have the filename, you can simply do
$newpath = "/folders/image.jpg";
$data = file_get_contents($_POST['fileName']);
file_put_contents($newpath, $data);
Rather then displaying it, save $_POST['image'] to the server, see File System
I have a code in my website to show remote Gravatar portraits or uploaded images. Uploaded is ok, but i can't get the gravatar images.
Cant use file_get_contents because it´s not allowed on my host.
Heres the start check for the file
if(file_exists($arUser['imagem'][0])){
$imgPath = $arUser['imagem'][0]; //Usar a imagem enviada
}elseif(!strlen($arUser['imagem'][0]) && checkRemoteFile('http://www.gravatar.com/avatar/'.md5($arUser['email'][0]).'fs=150')){
$imgPath = 'http://www.gravatar.com/avatar/'.md5($arUser['email'][0]).'fs=150';
}else
$imgPath = '../img/social_noavatar_150.jpg'; //Temporario
So this doesn´t work:
$imgData = getimagesize($imgPath);
$src = imagecreatefromwhatever($imgPath);
I know I should replace:
$imgPath = 'http://www.gravatar.com/avatar/'.md5($arUser['email'][0]).'fs=150';
with something like:
$imgPath = GetFileData('http://www.gravatar.com/avatar/'.md5($arUser['email'][0]).'fs=150');
or
*$imgPath = file_get_contents('http://www.gravatar.com/avatar/'.md5($arUser['email'][0]).'fs=150');*
Got error with both and I can´t create the image:
I´ve searched for the answer but the others didn't fited to me.
Sorry for my bad english. :(
Note:
function imagecreatefromwhatever($image){
$info = pathinfo($image);
$extension = strtolower($info['extension']);
switch($extension) {
case "jpg":
return imagecreatefromjpeg($image);
break;
case "jpeg":
return imagecreatefromjpeg($image);
break;
case "png":
return imagecreatefrompng($image);
break;
case "gif":
return imagecreatefromgif($image);
break;
default:
return imagecreatefromjpeg($image);
}
}
Well, if file_get_content is not available on your host, you might be out of luck. If this is a security feature on your host then you won't find a single function that allows you to get data from another server.
You might want to simply bypass the function and set your image src url to the gravatar one. Something like :
<img src="http://www.gravatar.com/avatar/<?=md5($arUser['email'][0]);?>&fs=150" width="150"/>
(Please double check the url, I added a & before the fs as it makes more sense, but I don't know how gravatar api url looks like)
This way it is the client browser that will make the request and not your server.
The easiest way I have found is to transfer the location:
if(checkRemoteFile('http://www.gravatar.com/avatar/'.md5($arUser['email'][0])))
header('Location: http://www.gravatar.com/avatar/'.md5($arUser['email'][0]).'fs='.$sizePic);
If your PHP security on your server prevents remote grabbing of files via file_get_contents(), then your next best option is a CURL call to get the file contents fed in perhaps.
If your host doesn't allow file_get_contents it's likely other methods will not work. From my experience the hosts will prevent any external socket connections from script. So check with the host first.
Assuming that is the issue, you could still echo out an tag with the src attribute to the same location you're trying to get in script.
<img src="<?php echo('http://www.gravatar.com/avatar/'.md5($arUser['email'][0]).'fs=150');?>" />
You could also use the same trick to put the url into a style if you don't want to use the tag.
I'm desperately trying to solve this one. I have a bunch of files stored outside of the webroot and I need to serve them to a user after a few auth checks. These files have been uploaded using a Flex application or have just been manually uploaded through FTP. I have a serving script that looks something like:
<?php
$filePath = '/for/demonstration/only.jpg';
...
$type = exif_imagetype($filePath);
$size = filesize($filePath);
if ($type && $size > 0) {
switch($type)
{
case IMAGETYPE_PNG:
header("Content-Type: image/png");
break;
case IMAGETYPE_JPEG:
header("Content-Type: image/jpeg");
break;
default:
header("Content-Type: text/plain");
break;
}
header("Content-Length: {$size}");
readfile($filePath);
exit;
} else {
echo 'error';
}
Pretty simple. The image however, somewhere in the upload process, Because of the encoding process, the file has gained an extra 100-130B, and now seems to be corrupted. I get the extraneous bytes error. The upload script is pretty simple as well, Flex uses FileRefrence for the user to select the file, then encodes the data and sends it to the server script:
<?php
function fileupload($data)
{
$daily_folder = 'today/';
$fileName_clipped = substr( $fileName, 0, $max_file_len );
$fileName_clipped = preg_replace('/\./','_',$fileName_clipped);
$filePath = '/path/to/storage' . $daily_folder;
if(!is_dir($filePath))
mkdir($filePath);
if( strlen($data->filedata) > 0 ) {
if( !file_put_contents($filePath . $fileName_clipped, base64_decode($data->filedata)) )
return false;
} else {
return false;
}
}
Running the process
file A: 31,740B in, 31,848B out, 108B extra
file B: 35,273B in, 31,403B out, 130B extra
I imagine this could be on the Flash side, but honestly it's dirt simple. I just don't see where the extra data is coming in, and why its corrupting the file. Anyone know why this is happening? or better yet, how I can clean these files up now?
Here's the dealio. When I backed up all the images from one server and moved them to another I FTPed all the files onto my Windows laptop. That process, whether because of Windows or perhaps FileZilla, corrupted all of the files. adding a bunch of junk onto them. I'd live input as to what you think caused the problem, but regardless I located the problem and fixed it.
The solution was to zip the parent directory on the server and download the zip. I didn't have to modify any code. Just a simple procedure revision. How lame.