Viewed   97 times

I want to allow registered users of a website (PHP) to upload files (documents), which are going to be publicly available for download. In this context, is the fact that I keep the file's original name a vulnerability ? If it is one, I would like to know why, and how to get rid of it.

 Answers

1

That depends where you store the filename. If you store the name in a database, in strictly typed variable, then HTML encode before you display it on a web page, there won't be any issues.

Wednesday, August 31, 2022
4

Glad you asked. This is a tricky subject, and few application developers are aware of the security risks.

I'll give you a summary of the approaches you should take, and some reading to learn more. Make sure you read the additional reading, because my summary is incomplete.

Summary:

  1. Host the user-uploaded content on a separate domain. This is the most important and reliable defense you can take.

  2. Check the MIME type of the uploaded file, when it is uploaded, to make sure it is on a whitelist of safe MIME types. Generate a new random filename to save it under. In the case of some file types, such as images, Consider re-coding it (e.g., transform to PNG, or use ImageMagick to convert it from its filetype to the same filetype), as this may defeat some attacks.

  3. When the file is downloaded/retrieved, make sure to set the Content-Type: header explicitly to the safe MIME type. Also set a X-Content-Type-Options: nosniff header. If you don't intend for the file to be viewed in the browser, send a Content-Disposition: attachment header, too, to make the browser treat it as a file download.

  4. Scan file uploads for viruses or malware.

Reading:

  • What steps should be taken to validate user uploaded images within an application?

  • MIME sniffing protection

  • Is it safe to store and replay user-provided mime types?

  • Is it safe to serve any user uploaded file under only white-listed MIME content types?

Friday, September 23, 2022
5

if a user has not selected a file the field would be empty you should be able to to error checking

if($_FILES["file"]["name"] != "") { THERE IS A FILE HERE } ELSE { ERROR USER DID NOT SELECT FILE }
Monday, November 28, 2022
 
swanand
 
3

Android does not give the original file name and file type using the above approach of mine and it is a security issue from android. So, i had to make below solution for retrieving the correct file name, file type, file size and the file data in base64.

You will need below four plugins:

  1. FileChooser
  2. File
  3. FilePath
  4. Base64

FileChooserAndroidProvider:

import {Injectable} from '@angular/core';
import {File, FileEntry, IFile} from "@ionic-native/file";
import {Base64} from "@ionic-native/base64";
import {FilePath} from "@ionic-native/file-path";
import {FileChooser} from "@ionic-native/file-chooser";


@Injectable()
export class FileChooserAndroidProvider {

  constructor(private base64: Base64, private filePath: FilePath, private file: File, private fileChooser: FileChooser) {
  }

  getFileInfo(): Promise<any> {
    return this.fileChooser.open().then((fileURI) => {
      return this.filePath.resolveNativePath(fileURI).then((filePath) => {
        return this.file.resolveLocalFilesystemUrl(filePath).then((fileEntry: FileEntry) => {
          return new Promise((resolve, reject) => {
            fileEntry.file(meta => resolve(meta), error => reject(error));
          });
        }).then((fileMeta: IFile) => {
          return new Promise((resolve, reject) => {
            return this.base64.encodeFile(filePath).then((base64Data) => {
              resolve({
                fileData: base64Data,
                fileName: fileMeta.name,
                fileSize: fileMeta.size,
                fileType: fileMeta.type
              })
            }).catch((error) => {
              reject(error);
            })
          })
        });
      });
    });
  }
}

FileChooserAndroidProviderModule:

import {NgModule} from '@angular/core';
import {Base64} from "@ionic-native/base64";
import {FileChooser} from "@ionic-native/file-chooser";
import {FilePath} from "@ionic-native/file-path";
import {File} from "@ionic-native/file";

@NgModule({
  declarations: [],
  exports: [],
  providers: [
    FileChooser,
    File,
    FilePath,
    Base64
  ]
})
export class FileChooserAndroidProviderModule {
}

SamplePage:

constructor(private fileChooserAndroid: FileChooserAndroidProvider){}

  uploadFileForAndroid(): void {
    this.fileChooserAndroid.getFileInfo().then((result) => {
      this.fileName = result.fileName;
      this.fileData = this.sanitizeFileData(result.fileData);
      this.fileSize = result.fileSize;
      this.fileType = result.fileType;
    }).catch((error) => {
      this.helperProvider.createAlert('Alert', 'File can not be uploaded.');
    });
  }

SamplePageModule:

@NgModule({
  declarations: [
    SamplePage
  ],
  imports: [
    FileChooserAndroidProviderModule
  ],
  providers: [
    FileChooserAndroidProvider
  ]
})
export class SamplePageModule {
}
Tuesday, December 27, 2022
3

You have to do the following:

  1. Move all the files out of the webroot. You could disable access to the folder with .htaccess, but it is not worth the hassle and potential security risk. Just move it out there.
  2. Keep a table of the files uploaded, storing the user's original file name there. Rename the file to $id.$ext and so on. In short, you don't want to use the user's file name in your system.
  3. Have a script, download.php or whatever, get the file's ID, verify who is logged in, and if everything checks out, fetch the file, read it out to the browser, and send the appropriate download headers.

These headers would be something like:

header('Content-type: application/octet-stream');
header('Content-disposition: attachment; filename=usersuppliedname.txt');
header("Content-Length: " . filesize('../safefiles/1.txt'));
header("Content-Transfer-Encoding:  binary");
readfile('../safefiles/1.txt');
exit;

You can then get more fancy if you want to allow resuming files and such, but the above should do it.

Thursday, September 29, 2022
 
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :