Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unaccessible administration panel due to mixed content with NGINX reverse proxy #2023

Closed
Braincoke opened this issue Aug 17, 2021 · 3 comments
Labels

Comments

@Braincoke
Copy link

PHP Version

7.4

Shopware Version

v6.4.3.0 Stable Version

Expected behaviour

Within a 'https' Shopware instance, the administration panel loads properly without the need for the user to disable some security feature in his browser.
Within a 'https' Shopware instance, the images in the storefront load properly without the need for the user to disable some security feature in his browser.

Actual behaviour

When trying to access the admin panel at "https://my-sw-proto.com/admin", some of the assets are being fetched in HTTP which causes a "Mixed Block" error and the page doesn't load.

Some examples of contents being fetched in HTTP:

This problem extends to the shopware customer interface. I am using shopware-pwa and my images don't load because they are being fetched in HTTP.

How to reproduce

I am trying to host Shopware (as a prototype) in a Docker container behind a NGINX reverse proxy.
I decided to use Dockware#play to do this:

version: "3"

services:
    shopware:
      image: dockware/play
      container_name: shopware
      ports:
         - "8383:80"
         - "8888:8888"
         - "9999:9999"
         - "9998:9998"
      networks:
         - web
networks:
  web:
    external: false

I configured my NGINX with X-Forwarded-Proto like so:

    server_name my-sw-proto.com;

    location / {
        proxy_hide_header Access-Control-Allow-Origin;
        proxy_hide_header Access-Control-Allow-Headers;
        proxy_hide_header Access-Control-Max-Age;
        proxy_hide_header Access-Control-Expose-Headers;
        add_header Access-Control-Allow-Origin * always;
        add_header Access-Control-Max-Age 3600;
        add_header Access-Control-Expose-Headers Content-Length;
        add_header Access-Control-Allow-Headers *;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Host $host:$server_port;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_pass http://127.0.0.1:8383;
    }

And I have a valid SSL certificate with Let's Encrypt and serve my site through https.

@Braincoke Braincoke added the Bug label Aug 17, 2021
@Braincoke
Copy link
Author

For the moment I workaround this issue by overriding the following files:

  • /var/www/html/.env
  • /var/www/html/vendor/shopware/administration/Resources/views/administration/index.html.twig
  • /var/www/html/vendor/shopware/storefront/Framework/Routing/RequestTransformer.php
  • /var/www/html/vendor/shopware/core/Content/Media/Pathname/UrlGenerator.php

In the env file, I added the APP_URL variable

APP_ENV=prod
APP_SECRET=1
INSTANCE_ID=1
DATABASE_URL=mysql://root:root@localhost:3306/shopware
APP_URL=https://my-sw-proto.com
MAILER_URL=smtp://localhost:1025
COMPOSER_HOME=/var/www/html/var/cache/composer
SHOPWARE_ES_ENABLED=0
TRUSTED_PROXIES=0.0.0.0                                 

In the index.html.twig I updated the URLs fetched with the "assets()" function to force the use of https. This modification allows me to access the admin panel.

    <link rel="stylesheet" href="{{ asset('static/css/vendors-node.css', '@Administration') | replace({'http': 'https'}) }}">
<script nonce="{{ cspNonce }}" src="{{ asset('static/js/vendors-node.js', '@Administration') | replace({'http': 'https'})  }}"></script>

I also hardcoded some URLs:

        apiContext: {
            host: '{{ app.request.host }}',
            port: {{ app.request.port }},
            scheme: 'https',
            schemeAndHttpHost: 'https://my-sw-proto.com',
            uri: 'https://my-sw-proto.com/admin',
            basePath: '{{ app.request.basePath }}',
            pathInfo: '{{ app.request.pathInfo }}',
            liveVersionId: '{{ liveVersionId }}',
            systemLanguageId: '{{ systemLanguageId }}',
            apiVersion: {{ apiVersion }},
            assetPath: 'https://my-sw-proto.com'
        },

In my UrlGenerator.php I modified the getBaseUrl() function to force the use of https. This gives me access to images in the customer frontend.

    private function getBaseUrl(): string
    {
        if (!$this->baseUrl) {
            $this->baseUrl = $this->createFallbackUrl();
        }

        // return $this->baseUrl;
        return str_replace('http', 'https', $this->baseUrl);
    }

In RequestTransformer.php I hardcoded the use of https in getSchemeAndHttpHost:

    private function getSchemeAndHttpHost(Request $request): string
    {
        return  'https://' . $this->punycode->decode($request->getHttpHost());
    }

My docker-compose looks like this in the end:

version: "3"

services:
    shopware:
      image: braincoke/dockware
      container_name: shopware
      ports:
         - "8383:80"
         - "8888:8888"
         - "9999:9999"
         - "9998:9998"
      volumes:
         - './env:/var/www/html/.env'
         - './index.html.twig:/var/www/html/vendor/shopware/administration/Resources/views/administration/index.html.twig'
         - './RequestTransformer.php:/var/www/html/vendor/shopware/storefront/Framework/Routing/RequestTransformer.php'
         - './UrlGenerator.php:/var/www/html/vendor/shopware/core/Content/Media/Pathname/UrlGenerator.php'
      networks:
         - web
networks:
  web:
    external: false

I am far from being a PHP developer, but from what I read, the app should probably use the header X-Forwarded-Proto to determine which scheme should be used.
I noticed that in Recovery/Update/src/Utils.php, it already does something similar:

    public static function getRealIpAddr()
    {
        if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
            $ip = $_SERVER['HTTP_CLIENT_IP'];
        } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
        } else {
            $ip = $_SERVER['REMOTE_ADDR'];
        }

        return $ip;
    }

@shyim
Copy link
Member

shyim commented Aug 17, 2021

@Braincoke
Copy link
Author

Thanks for the help.

In the end the problem was in my environment file, I should have set TRUSTED_PROXIES to REMOTE_ADDR instead of 0.0.0.0.

So now my env file looks like this:

APP_ENV=prod
APP_SECRET=1
INSTANCE_ID=1
DATABASE_URL=mysql://root:root@localhost:3306/shopware
APP_URL=https://my-sw-proto.com
MAILER_URL=smtp://localhost:1025
COMPOSER_HOME=/var/www/html/var/cache/composer
SHOPWARE_ES_ENABLED=0
TRUSTED_PROXIES=REMOTE_ADDR

And my docker-compose llke this:

version: "3"

services:
    shopware:
      image: braincoke/dockware
      container_name: shopware
      ports:
         - "8383:80"
         - "8888:8888"
         - "9999:9999"
         - "9998:9998"
      volumes:
         - './env:/var/www/html/.env'
      networks:
         - web
networks:
  web:
    external: false

Everything works fine now.
This issue helped: dockware/dockware#63

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants