SpartnerNL / Laravel-Nova-Excel

🚀 Supercharged Excel exports for Laravel Nova Resources
https://docs.laravel-excel.com/nova/1.0/
MIT License
378 stars 73 forks source link

[BUG] Trying to export selected rows returns failed - forbidden (only on PROD) #85

Closed mkantautas closed 4 years ago

mkantautas commented 4 years ago

Prerequisites

Versions

Description

On the production environment, I can't download the excel export - it ends up as failed - forbidden - without any errors. On local everything works perfectly.

On local(windows 10 pro WSL2 - ubuntu18.04lts) I don't use SSL(I don't think it might be the issue here), but noting it anyway.

Steps to Reproduce

I select some rows and go to actions and click download excel, I select the location where to download and get the file download pop up, but it's not successful in the end: image

Expected behavior:

It should actually download.

Actual behavior:

It doesn't.

Additional Information

My configuration for nova is pretty basic. My main app is an SPA(vuejs) and using Laravel as an API.

dmarkussen commented 4 years ago

This seems like a browser related issue to me. Not sure which browser you are using but I found this with a quick google search:

This error means you don't have permission to download this file from the server.

To fix, go to the website where the file is hosted. Check if you need to sign in (or provide some other authentication). If you can't sign in, contact the website or server owner, or try finding the file on a different site.

https://support.google.com/chrome/answer/2898334?hl=en

I would try changing the browser setting to allow you to choose the download location and try a different directory. You maybe downloading the file to a location that does not allow it; at least for that user.

I hope that is helpful.

smartens80 commented 4 years ago

I have the issue on staging and production servers. Works fine locally.

Its not a browser issue as it works locally on same browser

I have a feeling it's to do with permissions possibly when writing to the tmp directory on server?

Any advice?

Same version info as @neorganic

smartens80 commented 4 years ago

Hi @patrickbrouwers any chance you can take a look at this?

I've looked further into this and I can see the files being created in the /tmp directory with the appropriate permissions, however the download fails?

Can't seem to work out exactly why this occurs on staging / production servers but not locally.

arifulhb commented 4 years ago

I also have the same error. My app is also not so complicated. Laravel + Nova in Docker.

Works fine in local. But same forbidden error in staging. We didn't deployed the app in production.

In production, files are created in /tmp directory, but finally get the forbidden error.

patrickbrouwers commented 4 years ago

Have you tried using a different tmp folder? https://github.com/Maatwebsite/Laravel-Excel/blob/3.1/config/excel.php#L166

smartens80 commented 4 years ago

Have you tried using a different tmp folder? https://github.com/Maatwebsite/Laravel-Excel/blob/3.1/config/excel.php#L166

No luck with that either. I changed so that it was set to the 'storage' folder in Laravel and got same issue.

'local_path' => '/home/forge/my_site/storage',

I can't actually even see the file created now, where as before in /tmp I could at least see the file was created and stored on the server, but download fails.

arifulhb commented 4 years ago

Have you tried using a different tmp folder? https://github.com/Maatwebsite/Laravel-Excel/blob/3.1/config/excel.php#L166

I have exactly same result as @smartens80

In local, when my APP_ENV=local this is the URL which I can download

http://mysite.test/nova-api/users/action?action=export-user&pivotAction=false&search=&filters=W3siY2xhc3MiOiJBcHBcXE5vdmFcXEZpbHRlcnNcXFVzZXJcXEZyb21GaWx0ZXIiLCJ2YWx1ZSI6IiJ9LHsiY2xhc3MiOiJBcHBcXE5vdmFcXEZpbHRlcnNcXFVzZXJcXFRvRmlsdGVyIiwidmFsdWUiOiIifV0%3D&trashed=

But when I change APP_ENV=production I get redirected to this URL and get a 403 Access Denied.

https://mysite.test/nova-vendor/maatwebsite/laravel-nova-excel/download?expires=1587367491&filename=users-20200420-072350.xlsx&path=eyJpdiI6IkR1cVVod0Z1UjIzR2JKN3FxUXo1dUE9PSIsInZhbHVlIjoiVTdrcVlmbmNkZmgweG5wN1A3VGZhaGNcL1loXC9jUW84VHZtVFZFSFREZjdBTlQ2OHcxZzhNcDN4d05cL0xiRzg4am1pcFhUSURBTDdHTVwvY3dmckFzN2xnPT0iLCJtYWMiOiI3Nzk0MDEyNDg3YTZmMTIzZmUzMTYxYzBiYzU1MWU0N2RlMmUxNmI5ZDg1MGQyMDI1NWQ0NjU3NWE5YjBjY2U0In0%3D&signature=8ce49207adebb9b4e6e86962a1627ec40c3eca45a83b4a23fa62c9454a3451e3
arifulhb commented 4 years ago

I believe this #56 is related to this problem.

patrickbrouwers commented 4 years ago

If anything modifies the URL before clicking on it, the signature won't be valid and you can't download it. If the URL gets signed with http:// and the users opens it with https:// that won't work. Make sure to always use the same protocol when signing. Also make sure no middleware modify the download URL (like adding/removing GET params)

mkantautas commented 4 years ago

So trying to think that the fact that on prod my nova site is under domain https://api.mysite.com/nova/** and my APP_URL value is https://mysite.com may has something to do with this problem?

patrickbrouwers commented 4 years ago

Yes that could be possible. You could debug it by checking what the exact url is what is being signed and then checking what is being validated by Laravel.

jayge-ekenstam commented 4 years ago

I am using a subdomain but my APP_URL is set correctly. Is there any other ideas as to what could be causing this?

tvanro commented 4 years ago

Seems to be an issue with SSL...

My app is behind a reverse proxy and I'm forcing HTTPS by using URL::forceScheme('https') in the AppServiceProvider. Downloading the excel returns Failed - Forbidden.

When I deactivate URL::forceScheme('https'), the excel download works but then the download is served with http.

AppServiceProvider

public function boot()
{
    if (env('APP_ENV') !== 'local') {
        URL::forceScheme('https');
    }
}

Any idea to make the excel download work while forcing HTTPS behind a reverse proxy?

mkantautas commented 4 years ago
    public function boot()
    {
        $env  = config('app.env');
        if ( $env === 'production' || $env === 'dev') {
            URL::forceScheme('https');
        }

    }

I also have forced https - yeah I guess we got to the bottom of the issue.

tvanro commented 4 years ago

Hi @neorganic,

I did a bit more research on it and I found the following Laravel issue that Signed URL's are not respecting HTTPS when using URL::forceScheme('https');: https://github.com/laravel/framework/issues/28941

There was a pull request submitted for this but was closed: https://github.com/laravel/framework/pull/31434

However... The excel download works on my side now by correctly configuring TrustProxies instead of using URL::forceScheme('https');

/**
 * The trusted proxies for this application.
 *
 * @var string|array
 */
protected $proxies = '*';

https://laravel.com/docs/7.x/requests#configuring-trusted-proxies

Hope this will work for you as well.

cord commented 4 years ago

When using Cloudflare make sure to set SSL to full:

TLS | xomerge io | Account | Cloudflare - Web Performance   Security 2020-09-08 12-12-29

otherwise the http header HTTP_X_FORWARDED_PROTO is set to http, which then is making the request insecure

rasel-gen commented 4 years ago

When using Cloudflare make sure to set SSL to full:

TLS | xomerge io | Account | Cloudflare - Web Performance Security 2020-09-08 12-12-29

otherwise the http header HTTP_X_FORWARDED_PROTO is set to http, which then is making the request insecure

OMG, You have saved my life man.

joshca1 commented 3 years ago

It happened to me as well running on docker. I managed to make it work changing URL::forceScheme('https'); with $this->app['request']->server->set('HTTPS', true); like so:

`$env = config('app.env');

if ($env === 'production') { URL::forceScheme('https'); }

if ($env === 'production') { $this->app['request']->server->set('HTTPS', true); }`

Milkhan commented 3 years ago

None of these worked for me:(

bennyvdhoogen commented 2 years ago

Though out of the scope for this repo/package, perhaps this is of use to someone:

None of the above fixes worked for me either. For me the temporarily signed route generated for the download route was broken in the staging and production environments we use (the signature is invalid). Strangely enough, for my local environment everything is working in order.

I did some vendor debugging and found out that in Illuminate\Routing\UrlGenerator::hasCorrectSignature() the method $request->server->get('QUERY_STRING') returned a query string that contained duplicate key value pairs (so the path, expiration keys etc could be found twice in that string) but only on our staging and production environments.

Update: this appeared to be a webserver issue, which in our situation is duplicating query parameters in the query string before it reaches the Laravel router. This breaks the signature validation in Laravel 8.x as it now relies on the exact query string matching (which I believe is more secure), instead of having all the key/value pairs checked. I've checked our configuration and apparently an nginx redirect rule contained an unnecessary directive to add a duplicate set of query parameters. Removing this directive solved the 403 forbidden issues.

namnh06 commented 2 years ago

It happened to me as well running on docker. I managed to make it work changing URL::forceScheme('https'); with $this->app['request']->server->set('HTTPS', true); like so:

`$env = config('app.env');

if ($env === 'production') { URL::forceScheme('https'); }

if ($env === 'production') { $this->app['request']->server->set('HTTPS', true); }`

This worked for me, please find the file name /app/Providers/AppServiceProvider.php

Function boot:

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Schema::defaultstringLength(191);
        // TODO: Adding \Illuminate\Support\Facades\URL::forceScheme('https'); for PRODUCTION
    $this->app['request']->server->set('HTTPS', true);
   }

For Laravel nova & Nginx with SSL.

aminemeickel commented 1 year ago

It happened to me as well running on docker. I managed to make it work changing URL::forceScheme('https'); with $this->app['request']->server->set('HTTPS', true); like so:

`$env = config('app.env');

if ($env === 'production') { URL::forceScheme('https'); }

if ($env === 'production') { $this->app['request']->server->set('HTTPS', true); }`

This worked for me, please find the file name /app/Providers/AppServiceProvider.php

Function boot:

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Schema::defaultstringLength(191);
        // TODO: Adding \Illuminate\Support\Facades\URL::forceScheme('https'); for PRODUCTION
  $this->app['request']->server->set('HTTPS', true);
   }

For Laravel nova & Nginx with SSL.

I have been struggling with this issue for months but this worked for me