Search code examples
phppathdownloadpath-traversal

Prevent users to download other files by changing the path in a url query


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.


Solution

  • 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.