Php Laravel 403仅在Nginx Web服务器上的签名无效 问题
我正在通过从laravels文档复制和粘贴的laravels“temporarySignedRoute”函数创建签名URL,在我的web服务器上,URL显示为403无效签名。签名的URL在我的本地机器上工作,但在将其上载到我的测试服务器时,会出现如下所示的错误 我试过的 我一直在寻找一个解决方案有一段时间了,现在已经尝试了许多已经发布在堆栈溢出上的解决方案,但似乎没有什么能解决我的问题 我尝试了以下所有方法:Php Laravel 403仅在Nginx Web服务器上的签名无效 问题,php,laravel,nginx,https,Php,Laravel,Nginx,Https,我正在通过从laravels文档复制和粘贴的laravels“temporarySignedRoute”函数创建签名URL,在我的web服务器上,URL显示为403无效签名。签名的URL在我的本地机器上工作,但在将其上载到我的测试服务器时,会出现如下所示的错误 我试过的 我一直在寻找一个解决方案有一段时间了,现在已经尝试了许多已经发布在堆栈溢出上的解决方案,但似乎没有什么能解决我的问题 我尝试了以下所有方法: 通过AppServiceProvider强制所有路由到https,这强制所有url
- 通过AppServiceProvider强制所有路由到https,这强制所有url都是https,但给出了相同的结果
- 我试着改变Nginx的配置
- 我还尝试添加TrustProxies中间件,并将代理配置为“*”或全部,如laravel的文档中所述,结果相同
- 停止web服务器强制域使用https测试是否是https导致的,结果相同
vendor/laravel/framework/src/illumb/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服务器上传递,而是在我的本地服务器上传递。我注意到的另一件事是,web服务器令牌始终是相同的,无论发生什么情况都不会更改
可以查看我当前的Nginx配置
我当前的虚拟主机配置是。我认为这可能是问题所在。
尝试将配置文件中的位置块更改为
try_文件$uri$uri//index.php?$query_字符串代码>
我想您错过了?
,它位于索引和查询字符串之间
更新此文件并确保重新加载您的Nginx服务器。
sudo服务nginx重新加载
让我知道这是否有效 这不是Nginx错误。如果您检查illumb\Routing\Middleware\ValidateSignature
它抛出一个illumb\Routing\Exceptions\InvalidSignatureException
以403状态中止请求,这就是laravel处理无效签名URL的方式。我所做的,
创建了一个自定义签名中间件,该中间件扩展了实际的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\Http\Kernel.php$routeMiddleware
中的签名中间件更改为'signed'=>\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
@if($exception instanceof\App\Exceptions\InvalidEmailVerificationException)
断裂
验证令牌已过期。
@if(会话(“重新发送”))
{{{{{('新的验证链接已发送到您的电子邮件地址。')}
@恩迪夫
{{{$exception->getMessage()}
@恩迪夫
库马尔·巴恩瓦尔亲王的帖子修复了我当时的问题,我最近重新发现了这个问题的另一个版本,同时尝试在相同的设置中使用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);
}
}
下面是仅在已签名路由上运行的中间件
<?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);
}
}
我也不知道这是否是最好的修复方法,这是Laravel中一个非常模糊的bug。如果你有任何更好的解决方法的建议,我愿意接受建议
我以前的Github问题可能会有所帮助:您可以发布您的Nginx配置吗?我不确定,但它看起来像是Nginx配置中的一个问题。可以在这里查看当前的Nginx配置。您正在使用虚拟主机吗?因为上面提到的配置有根或服务器名或代理请求(如果您正在使用的话)?介意显示虚拟主机的配置吗?还有一件事,本地和服务器的.env有什么区别。我的意思是,会话驱动程序或缓存驱动程序引擎在这两个方面是不同的?数据库还是文件?服务器和本地中的.env几乎相同,减去指向不同MySQL服务器的SQL服务器的主机名。我使用的是数据库而不是文件。你可以在这里查看虚拟主机。尝试更改位置块以尝试\u文件$uri$uri//index.php?$query\u字符串;我认为您错过了索引和查询字符串之间的“?”。更新此文件并确保重新加载nginx服务器sudo service nginx reload`让我知道这是否有效。使用上述方法解决此问题后,我遇到了另一个问题,“UrlGenerator.php”中的签名在https上不同。我找到了这里详细介绍的解决方案。
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');
});