2

I am storing a converted base64 encoded string as an image file. I have to get the file as a string.

Currently I get the string via POST and I am worried about someone posting something that they might be able to use to compromise the sever. My question is how to make sure this is as secure as it can be.

This is how it works at the moment (summarised):

$encodedString = $_POST['image'];
// Strip the crud from the front of the string [1]
$encodedString = substr($encodedString,strpos($encodedString,",")+1);
// Cleanup File [2]
$encodedString = str_replace(' ','+',$encodedString);
// Decode string
$decoded = base64_decode($encodedString);
// Save File
file_put_contents(uniqid().'.png',$decoded);

What should I do next to ensure that someone doesn't/hasn't inject(ed) some malicious code into the post variable?

Or is there a better way than POST?

References:

  1. Convert Base64 string to an image file?
  2. PHP Data-URI to file
Community
  • 1
  • 1
Ben Harvey
  • 1,793
  • 2
  • 16
  • 23
  • 1
    http://stackoverflow.com/questions/602539/stop-people-uploading-malicious-php-files-via-forms and http://stackoverflow.com/questions/11061355/security-threats-with-uploads – Mike B Dec 13 '13 at 19:50
  • Great links! Thank you, they have been very helpful. – Ben Harvey Dec 13 '13 at 21:06

4 Answers4

4

After you write the file, feed the filename to imagecreatefrompng() or whatever other file format it might be. If it returns false, then it's not actually an image.

Aside from that, figure out how to format your POST request as multipart in the sending application and PHP will do the legwork to put it into the $_FILES superglobal along with the relevant information like filename and mime type. This will not help protect against any sort of code injection, though.

Sammitch
  • 30,782
  • 7
  • 50
  • 77
  • In conjunction with the other answers and comments I'm going to accept this, as I can use this technique to test for a valid image and remove any non image crud. – Ben Harvey Dec 13 '13 at 21:07
3

By giving the file an automatically generated name that the user can't influence, you have already avoided the worst issues.

Theoretically, it should not be possible to hack your server this way, since your server should not run any code in PNG files. Unfortunately, it is really easy to misconfigure nginx to do so. The correct solution to this is to configure nginx correctly, of course. You could attempt to do some filtering (e.g. detect <?php, but that risks false positives, i.e. legitimate images being rejected). I would maybe put a note into the documentation that people installing your software on nginx should really follow the instructions provided with the server and check for this issue, and wouldn't worry about it further. Note that it is possible to create a perfectly valid PNG file that does contain PHP code, so simply checking that the file is a valid image does not help here.

Now, to attacks against clients. Your server will (hopefully) serve the files with the correct MIME type. This should keep browsers from running it as code. Unfortunately, certain browsers (also known as "Internet Explorer") are dumb and try to guess the file type anyways. This will not hurt your server directly, but can cause user accounts of users using these browsers to get compromised. Thus, you may want to check the file type. If you can, serve all files with nosniff headers (e.g. by setting a corresponding htaccess or by serving them through fpassthru after setting the headers).

By loading and re-saving the image, you can make (more or less) sure that anything "nasty" in the image is gone. On the other hand, if someone finds an exploitable bug in your image library, they can hack your server, so it isn't without risk.

Jan Schejbal
  • 4,000
  • 19
  • 40
2

There is no security problem in $_POST'ed data (or any data at all, actually). It's just data, and you can safely save it in a file in your server.

The problem comes when you process that data in a unsecure-and-sometimes-easy way, perhaps with eval(), or echo it directly to the web browsers without escaping or tag removal, etc, etc, etc.

So if your issue is security, you're looking in the wrong place.

drmad
  • 530
  • 5
  • 16
  • 1
    Might also mention saving the files outside of webroot. Imagine uploading a php file then accessing it with the browser. – Mike B Dec 13 '13 at 19:52
  • I take your point, and I guess that was what the question was really about, I can't really store it outside of root as it's accessed through a regular `` tag instead of being served up by a script. – Ben Harvey Dec 13 '13 at 21:10
2
function get_base64_file_ext($base64ImageString)
{
    if(stristr($base64ImageString, 'image/png'))
        return 'png';
    if(stristr($base64ImageString, 'image/gif'))
        return 'gif';
    else
        return 'jpg';
}
function base64_to_file($base64ImageString)
{
    $data = explode(',', $base64ImageString);
    return base64_decode($data[1]); 
}
function save_base64_to_file($path, $filename, $base64ImageString)
{
    if(!stristr($base64ImageString, 'image/'))
        return 'No image found';
    $file_contents = base64_to_file($base64ImageString);
    //$file_contents = strip_tags($file_contents);

    $save_file = $path.$filename.'.'.get_base64_file_ext($base64ImageString);
    if(file_put_contents($save_file,$file_contents))
        return 'image saved successfully to '.$save_file;
    else
        return 'error while writing a file';
}

usage:

echo save_base64_to_file('/home/username/public_html/images/', 'my_image_file', $base64ImageString);