Bas Bas - 24 days ago 10
HTML Question

Invalid file extension when uploading from Sharepoint

I have a website up and running which makes use of file uploads. Everything is working fine, except for one of the users. They are using IE8 to upload files from their SharePoint server to the website. When I look at the $_FILES variable in PHP the 'name' key looks like this:

somefilename[1]


Instead of

somefilename.pdf


The uploads are then blocked, because the extension is not allowed. Has anyone ever dealt/seen this before? It looks like a temporary name, or a hidden file extension.

Edit:

Some of you requested the $_FILES variable:

[Filedata] => Array
(
[name] => Algemene%20Voorwaarden%20Corporate%20Services%202011[2]
[type] => application/octet-stream
[tmp_name] => /tmp/phps19zye
[error] => 0
[size] => 148021
)


This should be a PDF file. I need the extension, not only for security reasons, the [type] would be better suited for that, but also for presentation and functionality. I need to display the correct icon for a file type, and separate images for processing.

The HTML form is just a basic test form:

<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<form action="uploadtest3.php" method="post" enctype="multipart/form-data">
<input type="file" name="file_upload" id="file_upload" />
<br /><input type="submit" value="Uploaden" />
</form>
</body>
</html>


The PHP file is the following:

$targetFolder = '/uploadtests/uploads3';

if (!empty($_FILES)) {
$tempFile = $_FILES['file_upload']['tmp_name'];
$targetPath = $_SERVER['DOCUMENT_ROOT'] . $targetFolder;
$targetFile = $targetPath . $_FILES['file_upload']['name'];

move_uploaded_file($tempFile,$targetFile);
echo "OK";
}

Answer

Introduction

Have seen this issue before but am not sure what caused it. I would not even like to call it an error because some files extension can be intentionally removed or altered for malicious purpose.

The most important thing is validating file properly and worry less if a file has extension or not

Reasons :

  • File Extension Can easily be faked and it would be bad if your application relies on file extension only for validation

  • $_FILES ['file_upload']['type'] would return application/octet-stream for all files with not extension so it not not also a option for validation

  • Since its a browser issue then its a Client Related Problem so you don't have any control. If you are able to manage this you would definitely increase user experience

Simple Patch

The solution is very simple. All you need to validate your file with FILEINFO and fix any extension issue to your uploaded file.

You also need to validated all uploaded file based on their Mime Type ... and remove any invalid file.

Prove of Concept

$allowedTypes = array (
        "pdf" => "application/pdf" 
);

$pathFinal = "final";
$pathTemp = "temp";
try {
    if (! empty ( $_FILES )) {
        $tempFile = $_FILES ['file_upload'] ['tmp_name'];
        $fileName = $_FILES ['file_upload'] ['name'];
        $destinationTemp = $pathTemp . DIRECTORY_SEPARATOR . $fileName;
        $destinationFinal = $pathFinal . DIRECTORY_SEPARATOR . $fileName;
        /**
         * Move To tempary File
         */
        move_uploaded_file ( $tempFile, $destinationTemp );

        $fileMime = mimeInfo ( $destinationTemp );
        $key = array_search ( $fileMime, $allowedTypes );

        /**
         * Validate Mime Type
         */
        if (empty ( $key )) {
            unlink ( $destinationTemp );
            throw new Exception ( "File Type not Supported" );
        }

        /**
         * Fix Extention Issues
         */
        $ext = pathinfo ( $destinationTemp, PATHINFO_EXTENSION );

        if (empty ( $ext )) {
            $destinationFinal .= "." . $key;
        }

        /**
         * Transfer File to Original Location
         */
        copy ( $destinationTemp, $destinationFinal );
        unlink ( $destinationTemp );

        echo "OK";
    }
} catch ( Exception $e ) {
    echo "ERROR :", $e->getMessage ();
}

Function Used

function mimeInfo($file) {
    return finfo_file ( finfo_open ( FILEINFO_MIME_TYPE ), $file );
}
Comments