I have a laravel web that serve some file for authenticated user only but somehow hacker can get my .env file by Path Traversal. Here is my route under middleware auth group
Route::get('storage/{filename?}/download/',function($filename){
$basepath = storage_path($filename);
$path = realpath($basepath);
try {
if ($path !== false && substr($path, 0, strlen($basepath)) == $basepath){
$response = response()->download($path);
return $response;
}
} catch (\Throwable $err) {
abort(404);
}
})->where('filename','(.*)');
Route::get('storage/{filename?}',function($filename){
$basepath = storage_path($filename);
$path = realpath($basepath);
try {
if ($path !== false && substr($path, 0, strlen($basepath)) == $basepath){
$response = response()->file($path);
return $response;
}
} catch (\Throwable $err) {
abort(404);
}
})->where('filename','(.*)');
I write this route after reading an article from here but I dont know how to test if my app is free from path traversal attack. Is it enough only configuring my route like this or any additional setting? the only accessible storage is storage/app/files
CodePudding user response:
This is still not safe. example:
Psy Shell v0.10.8 (PHP 7.4.27 — cli) by Justin Hileman
>>> $basepath = storage_path('../.env');
=> "/usr/local/var/www/site-example/storage/../.env"
>>> $path = realpath($basepath);
=> "/usr/local/var/www/site-example/.env"
Just follow the guide you mentioned. basename
will strip the directories attached.
Psy Shell v0.10.8 (PHP 7.4.27 — cli) by Justin Hileman
>>> $fileName = basename('../.env');
=> ".env"
>>> $basepath = storage_path($fileName);
=> "/usr/local/var/www/site-example/storage/.env"
>>> $path = realpath($basepath);
=> false
>>>
false is returned if the file does not exist in the storage dir.
>> $fileName = basename('../.env');
=> ".env"
>>> $basepath = storage_path($fileName);
=> "/usr/local/var/www/example-site/storage/.env"
>>> $path = realpath($basepath);
=> false
>>> $fileName = basename('../test-file.pdf');
=> "test-file.pdf"
>>> $basepath = storage_path($fileName);
=> "/usr/local/var/www/example-site/storage/test-file.pdf"
>>> $path = realpath($basepath);
=> "/usr/local/var/www/example-site/storage/test-file.pdf"
>>>
CodePudding user response:
You can do a path check against storage path to avoid path traversal attacks after finding realpath of the requested file:
Like:
$fileName = "../.env";
$filePath = realpath(storage_path($fileName));
$storagePath = storage_path();
if (!$filePath) {
abort(404, "Not Found");
}
if (strpos($filePath, $storagePath) !== 0) {
abort(403, "Forbidden");
}