Подписанный маршрут Laravel 5.7 возвращает 403 недопустимую подпись

Я пытаюсь воспользоваться преимуществами нового подписанного промежуточного программного обеспечения в Laravel 5.7, но по какой-то причине сгенерированный подписанный URL-адрес возвращает 403 Invalid Signature.

Я использую последнюю версию Laravel с PHP 7.2

Это мой маршрут web.php:

Route::get('/report/{user}/{client}', function ($user, $client) {
    return ("El usuario es: $user y el cliente es: $client");
})->name('report.client')->middleware('signed');

и это в моем контроллере:

$objDemo->tempURL = Url::temporarySignedRoute('report.client', now('America/Panama')->addDays(5), [
            'user' => 1,
            'client' => 1
        ]);

URL-адрес создается и отображается примерно так:

https://example.com/report/1/1?expires=1545440368&signature=55ad67fa049a74fe8e123c664e50f53564b76154e2dd805c5927125f63c390a1

Но когда я нажимаю на ссылку, появляется сообщение 403 с сообщением: «Неверная подпись».

Любые идеи? заранее спасибо

-----------ОБНОВИТЬ------------

То, что я уже сделал:

  1. Попробуйте маршрут без подписи, работает отлично
  2. Попробуйте маршрут без параметров и только с подписью
  3. Пробовать маршрут без временной настройки и только подписывать
  4. Установите ip-адрес cloudflare на доверенные прокси
  5. Отключить HTTPS, Включить HTTPS

Кажется, ничего не работает, всегда появляется страница с неверной подписью 403

----------- ОБНОВЛЕНИЕ 2 ------------

Хорошо, поэтому после некоторого копания и тестирования я обнаружил, что подписанные маршруты laravel не будут работать, если пользователь вошел в систему, это странно, если я выхожу из системы, тогда маршрут работает отлично, но если я вхожу в систему, он показывает Ошибка 403, может быть, это связано с тем, что Laravel добавляет заголовок cookie сеанса после всего остального? и так подписанный маршрут не работает из-за этого? так оно и должно быть?

Странно, потому что, скажем, я хочу создать временную ссылку для моих пользователей, чтобы что-то загрузить, если они вошли в мое приложение Laravel, они получат это сообщение об ошибке 403 ... :(

------------ ОБНОВЛЕНИЕ 3 ------------------

Я пробовал новую установку laravel и работал отлично, так что это что-то из моего основного приложения Laravel, также попытался установить все зависимости композитора в свежую установку Laravel и по-прежнему отлично работал независимо от статуса входа пользователя, так что это не конфликт с моими зависимостями.

@LaraDev, ты копаешь абсолютно в правильном направлении.

Vinay Kaithwas 08.06.2020 08:48
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
7
1
15 520
9
Перейти к ответу Данный вопрос помечен как решенный

Ответы 9

Ответ принят как подходящий

После отладки UrlGenerator :: hasValidSignature () я закончил DD переменные внутри UrlGenerator.php следующим образом:

public function hasValidSignature(Request $request, $absolute = true)
    {
        $url = $absolute ? $request->url() : '/'.$request->path();

        //dd($url);

        $original = rtrim($url.'?'.Arr::query(
            Arr::except($request->query(), 'signature')
        ), '?');

        dd($original);
        $expires = Arr::get($request->query(), 'expires');

        $signature = hash_hmac('sha256', $original, call_user_func($this->keyResolver));

        return  hash_equals($signature, (string) $request->query('signature', '')) &&
               ! ($expires && Carbon::now()->getTimestamp() > $expires);
    }

переменная $original показала мне, что на самом деле происходит с моим URL-адресом, и показала следующее:

https://example.com/report/1/1?expires=1546586977&settings%5Bincrementing%5D=1&settings%5Bexists%5D=1&settings%5BwasRecentlyCreated%5D=0&settings%5Btimestamps%5D=1&profile%5Bincrementing%5D=1&profile%5Bexists%5D=1&profile%5BwasRecentlyCreated%5D=0&profile%5Btimestamps%5D=1&user%5Bincrementing%5D=1&user%5Bexists%5D=1&user%5BwasRecentlyCreated%5D=0&user%5Btimestamps%5D=1

как вы можете видеть, есть параметры после параметра expires, те параметры, которые были добавлены после создания маршрута, и это было проблемой, это произошло потому, что у меня было промежуточное программное обеспечение, дающее некоторую информацию таким представлениям, как это:

UserDataMiddleware.php

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\Auth;
use App\User;
use App\Setting;
use App\UserProfile;
use Illuminate\Support\Facades\View;

class UserData
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {

        if (Auth::check()) {
            $settings = Setting::where('user_id', Auth::user()->id)->first();
            $profile = UserProfile::where('user_id', Auth::id())->first();
            $user = Auth::user();

            View::share('settings', $settings); //Another way to share variables, with the View::share
            View::share('profile', $profile);

            //Now we need to share owr variables trough the REQUEST to our controllers
            $request->merge([
                'settings' => $settings,
                'profile' => $profile,
                'user' => $user
            ]);


        }
        return $next($request);
    }
}

это промежуточное программное обеспечение было внутри групп промежуточного программного обеспечения, так что, надеюсь, это была проблема, если кто-то в будущем экспериментирует с этим, он сможет сначала это проверить.

Я знаю, что это давно опубликовано, но это спасло мне жизнь. Я бы никогда об этом не подумал, так что спасибо!

Andreas 02.02.2020 17:29

@Andreas, нет проблем, это цель этого ... я помню, что мне было трудно понять проблему, но я сделал это после долгих поисков.

NaturalDevCR 03.02.2020 18:14

Если вы используете Heroku, AWS или любой другой сервис, использующий LoadBalancer. Также убедитесь, что прокси-сервер, подключенный к вашему приложению, является доверенным.

Подробнее см. этот ответ.

Попробуйте код ниже:

class TrustProxies extends Middleware
{
    protected $proxies = '*';
    protected $headers = Request::HEADER_X_FORWARDED_ALL;
}

отредактируйте TrustProxies.php middleware. замените защищенный код $ proxies на защищенный $ proxies = '*'; это поможет решить ошибку 403 на laravel.

developer avijit 08.07.2019 14:32

@developer_avijit - может быть, попробуйте включить свой комментарий как часть ответа?

wakey 08.07.2019 14:38

По иронии судьбы, я последний раз пробовал этот ответ .. Спасибо, сработало! Было бы полезно, если бы Laravel зарегистрировал ошибку.

MrMedicine 11.12.2019 10:27

По сути, ваши подписи не совпадали, потому что URL-адрес, который вы сгенерировали с помощью \ Illuminate \ Support \ Facades \ URL :: signedRoute, был изменен вашим промежуточным программным обеспечением, что означает, что когда дело дошло до проверки $ request-> hasValidSignature (), это вернуло false.

У меня была аналогичная проблема, когда SendGrid добавлял строки запроса отслеживания UTM к URL-адресу в моем электронном письме (& utm_campaign = website & utm_source = sendgrid.com & utm_medium = email), что изменяло URL-адрес и, в конечном итоге, меняло подпись.

Во время взлома я добавил в свой контроллер следующий код, чтобы убрать дополнительные параметры запроса и повторно использовать подпись:

// Fix issue with sendgrid highjacking signed URL's with extra query params..
if ($request->query('utm_campaign')) {
    $sig = $request->query('signature', '');
    $url = route('route-key') . '?signature=' . $sig;

    return redirect($url);
}

у меня была похожая проблема в сумерках, и это был APP_KEY в .env.dusk.testing, который не соответствовал APP_KEY в .env

У меня только что возникла эта проблема, и оказалось, что пустые параметры в URL-адресе никогда не проверяются. Итак, когда вы это сделаете:

URL::temporarySignedRoute('newsletter.verify', now()->addDays(3), ['name' => $name, 'email' => $email])

но имя - это пустая строка (потому что это не обязательно), URL-адрес будет сгенерирован с помощью name= как часть строки запроса, но этот код внутри Laravel

$original = rtrim($url.'?'.Arr::query(Arr::except($request->query(), 'signature')), '?');

не вернет пустой name, поэтому URL-адрес был «изменен» и проверка не прошла. Часто используемое промежуточное ПО ConvertEmptyStringsToNull может иметь какое-то отношение к этому.

У меня была такая же проблема, и я сходил с ума, пока не наткнулся на ответ @LaravDev.

Примечание: я использую Laravel 7, который отличается от страницы web.php.

Мой исходный код выглядел так, который, по сути, просто добавляет переменную к запросу, чтобы мои представления не отображали боковую панель.

Route::middleware(['noSidebar'])->group(function()
{
    Auth::routes(['verify' => true]);
});

Мне пришлось удалить шорткод Auth :: routes () и переключить его на полный стек маршрутов Auth. (Обратите внимание, это отличается для каждой версии Laravel)

Route::middleware(['noSidebar'])->group(function()
{

// Authentication Routes...
Route::get('login', 'Auth\LoginController@showLoginForm')->name('login');
Route::post('login', 'Auth\LoginController@login');
Route::post('logout', 'Auth\LoginController@logout')->name('logout');

// Registration Routes...
Route::get('register', 'Auth\RegisterController@showRegistrationForm')->name('register');
Route::post('register', 'Auth\RegisterController@register');

// Password Reset Routes...
Route::get('password/reset', 'Auth\ForgotPasswordController@showLinkRequestForm')->name('password.request');
Route::post('password/email', 'Auth\ForgotPasswordController@sendResetLinkEmail')->name('password.email');
Route::post('password/reset', 'Auth\ResetPasswordController@reset')->name('password.update');

// Confirm Password (added in v6.2)
Route::get('password/confirm', 'Auth\ConfirmPasswordController@showConfirmForm')->name('password.confirm');
Route::post('password/confirm', 'Auth\ConfirmPasswordController@confirm');

// Email Verification Routes...
Route::get('email/verify', 'Auth\VerificationController@show')->name('verification.notice');
Route::post('email/resend', 'Auth\VerificationController@resend')->name('verification.resend');
    
});



//Moved the routes with tokens in the URL to outside my middleware grouping.

Route::get('email/verify/{id}/{hash}', 'Auth\VerificationController@verify')->name('verification.verify');
Route::get('password/reset/{token}', 'Auth\ResetPasswordController@showResetForm')->name('password.reset');

Тада работает! Спасибо вам всем

Спасибо, я сошел с ума! Я помещал туда свой подписанный URL: Route::localizedGroup(function () {})

jartaud 11.03.2021 03:22

У меня был APP_URL=http://localhost в файле .env. Когда я изменил значение на URL-адрес с сервера, проблема была решена.

Я использовал Laravel 8+.

ПОНЯТИЕ СПОСОБА ПРОВЕРКИ ЭЛЕКТРОННОЙ ПОЧТЫ LARAVEL

Понимание способа проверки может помочь вам просто решить эту ошибку.

laravel создает временный подписанный URL-адрес, используя метод URL::temporarySignedRoute(),

этот метод вызывается в verificationUrl(), расположенном по адресу \vendor\laravel\framework\src\Illuminate\Auth\Notifications\VerifyEmail.php.

/**
 * Get the verification URL for the given notifiable.
 *
 * @param mixed $notifiable
 * @return string
 */
protected function verificationUrl($notifiable)
{
   return URL::temporarySignedRoute(
        'verification.verify',
        Carbon::now()->addMinutes(Config::get('auth.verification.expire', 60)),
        [
            'id' => $notifiable->getKey(),
            'hash' => sha1($notifiable->getEmailForVerification()),
        ]
    );
}

URL::temporarySignedRoute() создает URL-адреса в соответствии с config('app.url), для которого по умолчанию установлено значение .env('APP_URL').

Итак, если URL-адрес, отправляемый в электронные письма, отличается от URL-адреса, который будет получен laravel во время проверки (время проверки подписи URL-адреса), 403 | возникает недействительная подпись.

Пример:

  • если вы установите APP_URL на http://yourdomain.com/, ссылка для подтверждения должна выглядеть как http://yourdomain.com/email/verify/{id}/{hash}. теперь, если вы настроите свои конфигурации сервера для перенаправления на https, возникнет недопустимая подпись, поскольку URL-адрес, который получает laravel, - это https://yourdomain.com/email/verify/{id}/{hash}, а не такой же, как URL-адрес проверки электронной почты.

Другие вопросы по теме