Ben Harvey
Ben Harvey

Reputation: 1843

Securely save a base64 string to a file in php

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

Upvotes: 2

Views: 5176

Answers (4)

user3601800
user3601800

Reputation: 31

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);

Upvotes: 2

Jan Schejbal
Jan Schejbal

Reputation: 4033

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.

Upvotes: 3

drmad
drmad

Reputation: 620

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.

Upvotes: 2

Sammitch
Sammitch

Reputation: 32232

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.

Upvotes: 4

Related Questions