-4

i have a download function receiving the filename by $_GET and i want to prevent users of downloading other files changing the path and accessing other files in the system.

method:

function actionDownload($arquivo) {
    try {
        $filepath = \Yii::getAlias('@webroot') . '/files/coordenadas/'. $arquivo;
        if (file_exists($filepath)){
            return \Yii::$app->getResponse()->sendFile(\Yii::getAlias('@webroot') . '/files/coordenadas/'. $arquivo, $arquivo);
        }
    }
    catch (\Exception $exception) {
        throw new NotFoundHttpException("Arquivo não encontrado");
    }
}

the route to download the method:

http://example.com/converter-coordenadas/download?arquivo=geografica-utm-20200830171051.xlsx

if someone change the arquivo variable to another valid path it will be able to download other files. How prevent that, but keeping the function receiving the file name in a url param?

the situation that i have is:

  1. the user upload a file through ajax
  2. i convert this file and return the filename
  3. create a download button with the link to the new file.

I don't have any other information to make a relation with the file, like an user id.

André Walker
  • 588
  • 10
  • 30
  • 4
    Probably not have your download file exposed in url at all. Instead have an `id` that references the file – GetSet Aug 30 '20 at 21:38
  • 1
    Or you can encrypt the filename and store in separate DB field along with original name at the time when you save the file, and show user only encrypted name. In your action you check if hash exist in DB and get needed original filename. Same technic is used on restore password or validate email address. You can take a look there. – Serghei Leonenco Aug 30 '20 at 22:10
  • I was hoping getting a lazy way to do it, using something native in php to only allow to access the path that i want, but that is a more elegant way. thanks @SergheiLeonenco – André Walker Aug 30 '20 at 22:40
  • 1
    You are very welcome – Serghei Leonenco Aug 30 '20 at 22:41

1 Answers1

1

As @GetSet explained in the comments, the biggest problem is procedural. One way to do this correctly is as follows:

  1. Upload the file to your server and save the reference in database (you already doing) and generate an unique ID for this file (or for this download). This ID will be saved in a database field, for example with the name: "donwload_id"

  2. Then in the view (when you are creating the link for the download):

    Html::a('Download', [Url::to('donwload-action'), 'download_id' => $model- >download_id]);

  3. In your controller, You will know how to find the file by its unique identifier (download_id).

No one knows how you have generated this ID and therefore it is more difficult for anyone to be able to generate it again. Also you can limit the time available to download the file by setting an expiration date to the link.

Dan A.S.
  • 654
  • 8
  • 24