LinkStackOrg / LinkStack

LinkStack - the ultimate solution for creating a personalized & professional profile page. Showcase all your important links in one place, forget the limitation of one link on social media. Set up your personal site on your own server with just a few clicks.
https://linkstack.org
GNU Affero General Public License v3.0
2.23k stars 228 forks source link

Error 403: Invalid Signature upon verification #696

Open brknkfr opened 7 months ago

brknkfr commented 7 months ago

LinkStack version

4.7.1

Description

E-Mail verification does not work. It always results in an 403 error. Probably same issue as in https://github.com/LinkStackOrg/LinkStack/issues/591, which is not fixed, but where you can find some possible workarounds.

Details about your system

LEMP stack on a debian bookworm system (nginx 1.22.1, php 8.2.7) with smtp mailing system.

Front end nginx proxy (ssl termination) configuration, listens on https and passes requests to backend, listening on http with IP address 123.123.123.1.

server {
    listen 80;
    listen [::]:80;
    server_name domain.tld www.domain.tld;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name domain.tld www.domain.tld;

    location / {
                proxy_set_header Host $http_host;
                proxy_set_header X-Forwarded-Host $http_host;
                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://123.123.123.123;
        proxy_set_header X-VerifiedViaNginx yes;
        proxy_read_timeout 60;
        proxy_connect_timeout 60;
        proxy_redirect off;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_cache_bypass $http_upgrade;
        add_header 'Content-Security-Policy' 'upgrade-insecure-requests';
    }
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/domain.tld/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/domain.tld/privkey.pem; # managed by Certbot
}

Back end nginx configuration for LinkStack, only listens on http with IP address 123.123.123.1

server {
    listen 80;
    server_name domain.tld www.domain.tld;
    root /var/www/domain.tld/linkstack;

    index index.php;

    charset utf-8;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    error_page 404 /index.php;

        location ~ \.php$ {
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_index index.php;
        include /etc/nginx/fastcgi_params;
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
        }
    location ~ /\.(?!well-known).* {
        deny all;
    }
    location ~ ^\. {
        deny all;
    }
    location ~ \.sqlite$ {
        deny all;
    }
    location ~ \.env$ {
        deny all;
    }
    location ~ /\.htaccess {
        allow all;
    }
}

How to reproduce

Configure system as described (debian bookworm with lemp stack)

Ugly workarounds

Possible Solution

Make LinkStack aware that it could be behind a (ssl) proxy.

lastsamurai26 commented 7 months ago

You need to forword all traffic with https (ssl)

internet 443-> nginx 443-> docker

After then you need to set FORCE_HTTPS=true

should you not use Docker then I wonder why you specify an ip in the config ?

brknkfr commented 7 months ago

You need to forword all traffic with https (ssl)

It should be possible to forward internal traffic on http only. There is no need for an encrypted connection to the backend server in my environment.

internet 443-> nginx 443-> docker

I don't use docker.

After then you need to set FORCE_HTTPS=true

should you not use Docker then I wonder why you specify an ip in the config ?

Because it's the IP address of the internal backend app server where LinkStack is running.

lastsamurai26 commented 7 months ago

how do you installed linkstack? if you have a webserver so you don't need to forward anything. Like this for http to https

server {

    listen 80 default_server;
    server_name _;
    return 301 https://$host$request_uri;
}

https

server {
    listen 443;
    listen [::]:443;
    server_name example.com;
    root /path/to/example.com;

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-Content-Type-Options "nosniff";

    index index.php;

    charset utf-8;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    error_page 404 /index.php;

    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~ /\.(?!well-known).* {
        deny all;
    }

location ~ ^\. {
deny all;
}

location ~ \.sqlite$ {
deny all;
}

location ~ \.env$ {
deny all;
}

location ~ /\.htaccess {
allow all;
}

}
brknkfr commented 7 months ago

I have two webservers: One as public front end server, responsible for ssl termination (https connections) and another one as an internal app server, responsible for the applications (LimeStack, php stuff).

It has to be an issue with the LinkStack karavel proxy configuration or proxy detection. When I set the proxy IP address of the front end server in app/Http/Middleware/TrustProxies.php with protected $proxies = [ '123.123.123.1']; where 123.123.123.1 is the IP address of the front end server, the verification links work as expected. So does it with protected $proxies = '*';

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

troykelly commented 2 months ago

Setting the trusted proxies via a variable would be desirable.

I've made this change:

<?php

namespace App\Http\Middleware;

use Fideloper\Proxy\TrustProxies as Middleware;
use Illuminate\Http\Request;

class TrustProxies extends Middleware
{
    /**
     * The trusted proxies for this application.
     *
     * @var array|string|null
     */
    protected $proxies;

    /**
     * The headers that should be used to detect proxies.
     *
     * @var int
     */
    protected $headers = Request::HEADER_X_FORWARDED_FOR 
        | Request::HEADER_X_FORWARDED_HOST 
        | Request::HEADER_X_FORWARDED_PORT 
        | Request::HEADER_X_FORWARDED_PROTO 
        | Request::HEADER_X_FORWARDED_AWS_ELB;

    /**
     * Create a new middleware instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->proxies = $this->parseProxies(env('TRUSTED_PROXIES'));
    }

    /**
     * Parse the environment variable containing the trusted proxies.
     *
     * @param string|null $proxies
     * @return array|string|null
     */
    protected function parseProxies($proxies)
    {
        if ($proxies === null) {
            return null;
        }

        if ($proxies === '*') {
            return '*';  // Explicitly handle the wildcard case
        }

        return array_map('trim', explode(',', $proxies));
    }
}