【问题标题】:Laravel 403 Invalid Signature only on Nginx Web ServerLaravel 403 无效签名仅在 Nginx Web 服务器上
【发布时间】:2019-11-04 09:29:20
【问题描述】:

问题

我正在通过从 laravel signed routes 文档中复制和粘贴的 laravel 'temporarySignedRoute' 函数创建一个签名 URL,在我的 Web 服务器上,该 URL 出现 403 无效签名。签名的 URL 在我的本地机器上工作,但在将其上传到我的测试服务器后,它会给出如下所示的错误。

我尝试过的

我一直在寻找解决方案一段时间,并尝试了许多已在堆栈溢出上发布的解决方案,但似乎没有任何解决方案可以解决我的问题。

我已经尝试了以下所有方法:

  • 强制通过 AppServiceProvider 到 https 的所有路由,这会强制所有 url 为 https,但结果相同。
  • 我尝试按照here 的描述更改 Nginx 的配置。

  • 我还尝试添加 TrustProxies 中间件,其代理配置为 '*' 或全部,如 laravel 在 Trust Proxies 上的文档中所述,结果相同。

  • 阻止网络服务器强制域使用 https 以测试是否只是 https 导致的,结果相同。

-- 更新--

我进入vendor/laravel/framework/src/Illuminate/Routing/UrlGenerator.php,同时试图四处寻找项目中的任何线索。我决定将它在本地和托管项目上比较的令牌数据转储(dd)出来,这就是结果。代码如下所示。

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

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

    $expires = $request->query('expires');

    $signature = hash_hmac('sha256', $original, call_user_func($this->keyResolver));
    dd($signature . " :: " . $request->query('signature', ''));
    return  hash_equals($signature, (string) $request->query('signature', '')) &&
           ! ($expires && Carbon::now()->getTimestamp() > $expires);
}

本地项目

托管项目

所以令牌没有在我的网络服务器上传递,而是在我的本地。另外我注意到的另一件事是 Web 服务器令牌始终相同,并且无论如何都不会更改。

我当前的Nginx配置可以查看here

我当前的虚拟主机配置是here

【问题讨论】:

  • 你能发布你的 Nginx 配置吗?我不确定,但它看起来像是 Nginx 配置中的一个问题。
  • 当前 Nginx 配置可以在这里查看。 drive.google.com/file/d/…
  • 您使用的是虚拟主机吗?因为上面提到的配置有一个 Root 或 servername 或 Proxy 请求(如果你正在使用) .. ?介意显示虚拟主机的配置吗?还有一件事是本地和服务器的.env有什么区别。我的意思是像 SESSION DRIVER 或 CACHE DRIVER 引擎在两者中都不同?数据库还是文件?
  • 服务器端和本地端的 .env 几乎完全相同,减去指向不同 MySQL 服务器的 SQL 服务器的主机名。我使用的是数据库而不是文件。您可以在此处查看虚拟主机。 docs.google.com/document/d/…
  • 尝试将您的位置块更改为 try_files $uri $uri/ /index.php?$query_string;我想你错过了'?在索引和查询字符串之间。更新这个并确保重新加载你的 nginx 服务器。 ` sudo service nginx reload ` 让我知道这是否有效。

标签: php laravel nginx https


【解决方案1】:

我认为这可能是问题所在。 尝试将配置文件中的位置块更改为

try_files $uri $uri/ /index.php?$query_string;

我认为您错过了索引和查询字符串之间的?

更新此内容并确保重新加载您的 Nginx 服务器。 sudo service nginx reload

让我知道这是否有效。

【讨论】:

  • 使用上述方法解决后,我遇到了另一个问题,即“UrlGenerator.php”中的签名在https上不同。我找到了这里详细介绍的解决方案,github.com/laravel/framework/issues/28941
【解决方案2】:

Kumar Barnwal 王子的帖子解决了我当时的问题,我最近在尝试在相同设置中使用 docker 时重新发现了这个问题的另一个版本,我想我会把它贴在这里以防万一有人遇到同样的问题。

我们正在使用代理服务器并在其上验证我们的 docker laravel 项目,所有项目都设置了 TrustProxies,然后我们在 AppServiceProvider.php 中强制使用 HTTPS,这使得 AJAX 调用正常工作。这会导致问题,因为项目本身没有加密,但它生成的所有 url 都认为它是因为我们强制它。当代理在请求中传递 URL 时,它是 http,当项目需要 HTTPS 时。

我找到了一个解决方案,它不是最干净的,他们的解决方案可能更好,但我制作了一个中间件,用于所有项目签名的路由,基本上它只是更改请求中的 url 以确保安全如果项目正在生产中。这不是不安全的,因为代理会处理安全性,并且仅在签名路由上。

以下是仅在签名路由上运行的中间件。

<?php

namespace App\Http\Middleware;

use Closure;

class SecureSignedURL
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if(config('app.env') === 'production' || config('app.env') === 'staging') {
            $request->server->set('HTTPS', 'ON');
        }
        return $next($request);
    }
}

我的web.php 与中间件,在我的Kernel.php 中定义为secure_signed_url

Route::group(['middleware' => ['secure_signed_Url', 'signed']], function () {
        route::get('/exampleurl1', 'TestController@route_exampleurl1_signed')->name('exampleurl1.signed');
        route::get('/exampleurl2', 'Template\TemplateController@route_exampleurl2_signed')->name('exampleurl2.signed');
});

我不知道这是否是最好的解决方法,这是 Laravel 中一个非常晦涩的错误。如果您对解决此问题的更好方法有任何建议,我愿意接受建议。

可能有帮助的我的旧 Github 问题:https://github.com/laravel/framework/pull/31434

【讨论】:

    【解决方案3】:

    这不是 Nginx 错误。如果您检查 Illuminate\Routing\Middleware\ValidateSignature,这就是 laravel 处理无效签名 url 的方式,它会抛出一个 Illuminate\Routing\Exceptions\InvalidSignatureException,它会以 403 状态中止请求。我做了什么, 创建了一个自定义签名中间件,它扩展了实际的 ValidateSignature

    <?php
    
    namespace App\Http\Middleware;
    
    use App\Exceptions\InvalidEmailVerificationException;
    use Closure;
    use Illuminate\Routing\Middleware\ValidateSignature as MiddleWare;
    
    class ValidateSignature extends Middleware
    {
        /**
         * Handle an incoming request.
         *
         * @param  \Illuminate\Http\Request  $request
         * @param  \Closure  $next
         * @return mixed
         */
        public function handle($request, Closure $next)
        {
            if ($request->hasValidSignature()) {
                return $next($request);
            }
    
            throw new InvalidEmailVerificationException;
        }
    }
    

    抛出一个自定义的App\Exceptions\InvalidEmailVerificationException

    <?php
    
    namespace App\Exceptions;
    
    use Symfony\Component\HttpKernel\Exception\HttpException;;
    
    class InvalidEmailVerificationException extends HttpException
    {
        /**
         * Create a new exception instance.
         *
         * @return void
         */
        public function __construct()
        {
            parent::__construct(403, 'Your email verification token seems to be invalid.');
        }
    }
    

    然后将App\Http\Kernel.php $routeMiddleware 中的签名中间件更改为'signed' =&gt; \App\Http\Middleware\ValidateSignature::class,

    在您的 403.blade.php 视图中,您可以将消息显示为

    @if ($exception instanceof \App\Exceptions\InvalidEmailVerificationException)
                                <h1 class="text-ginormous">Snap!</h1>
                                <h4 class="quick-error-description">Verification token expired.</h4>
                                @if (session('resent'))
                                    <div class="alert alert-success" role="alert">
                                        {{ __('A fresh verification link has been sent to your email address.') }}
                                    </div>
                                @endif
                                <p class="error-description">{{ $exception->getMessage() }}</p>
    
                                <a href="{{ route('verification.resend') }}" class="button-solid button-error mb-3" data-no-pjax>Email me a new link</a>
    @endif
    

    【讨论】:

      猜你喜欢
      • 2019-05-22
      • 1970-01-01
      • 2013-05-31
      • 1970-01-01
      • 2016-02-09
      • 1970-01-01
      • 2021-06-22
      • 1970-01-01
      • 2019-09-28
      相关资源
      最近更新 更多