Laravel 419 错误-VerifyCsrfToken 问题

Posted

技术标签:

【中文标题】Laravel 419 错误-VerifyCsrfToken 问题【英文标题】:Laravel 419 Error - VerifyCsrfToken issue 【发布时间】:2019-03-16 19:16:57 【问题描述】:

我在同一台服务器上托管了多个 Laravel 站点。在我创建的最新站点中,联系表单拒绝提交而不会引发 419 错误。我已经在我的 web.php 文件中设置了路由,就像其他网站一样,这些网站具有实时、有效的联系表单,并且我生成和发送令牌的方式完全相同 - 使用 csrf_field()

我找到了一个类似问题的答案,指出您可以通过将条目添加到 app/Http/Middleware/VerifyCsrfToken.php 中的 $except 数组来禁用 Csrf 检查。我已经验证这确实解决了 419 错误:

protected $except = [
    'contact',
    'contact*',
];

但我当然希望保留 Csrf 功能,并且我只更新了 $except 数组以用于故障排除值。

有谁知道尽管传递了生成的令牌,但新的 Laravel 环境可能会有这种 419 行为的不同之处?我已经尝试更新许多 ENV 设置并切换不同的东西,但除了修改 $except 数组之外没有其他任何影响。

更新

由于到目前为止已经进行了一些讨论,我想我会提供一些额外的信息和代码。

首先,这是一个 ajax 表单,但现在不要跳出你的座位。我一直在测试有无 ajax 的表单。如果我想使用 ajax 进行测试,我只需单击连接到 jQuery 侦听器的按钮。如果没有,我更改或删除按钮的 ID,或在控制台窗口中运行 $("#formName").submit();

上述(ajax、老式提交和带有.submit(); 的 jquery 选择器)都导致完全相同的响应 - 419 错误。

为了完整起见,这是我的 ajax 代码,它可以在我托管的所有其他网站上运行。我定义了一个 postData 数组来保持它的整洁,并在它之后直接添加了一个 console.log() 语句,以(再次)确认令牌生成得很好并且与请求一起正确传递。

var postData = 
            
    name: $("#name").val(),
    email: $("#email").val(),
    message: $("#message").val(),

    _token: $("input[name=_token]").val()

;

console.log(postData);


$.post("/contact", postData, function (data) 

...

有什么想法吗?我的 ENV 或其他文件是否存在配置问题?

进度更新!

因为其他站点运行良好,所以我克隆了一个旧站点并简单地覆盖了我为新站点更改的文件,然后 bam!它现在正在工作。进行了更多挖掘,我在站点的克隆版本与非工作版本上运行了php artisan --version,结果如下:

工作版本:Laravel 框架 5.7.3

非工作版本:Laravel Framework 5.7.9

也许这是 Laravel 的一个错误?或者我服务器上的某些包已经过时,需要更新才能与新版本的 Laravel 一起使用?

【问题讨论】:

假设 CSRF 验证我猜你已经在 web.php 而不是在 api.php 中设置了这些路由? 是的,在web.php我有以下两条路线:Route::get('/contact', 'ContactController@index');Route::post('/contact', 'ContactController@contactSubmit'); 您是否看到 _token 值被发送到 POST 路由? dd($request->all())contactSubmit 函数中,并确保它被正确发送。 我在发布这个问题之前添加了dd($request->all()),并且在我的本地开发环境中它正确显示了json输出,包括_token。但是,在服务器上,它甚至不会到达dd(),因为它在执行contactSubmit() 方法中的第一行代码之前就抛出了419 错误。但是我服务器上托管的其他网站上的其他联系表格可以正常工作,没有任何问题。 @Chad 您是否看到_token 在浏览器的网络检查器的“网络”选项卡中随请求一起发送? 【参考方案1】:

TLDR:这篇文章包含许多潜在的问题和修复;它适用于那些在卡住时搜索相关奖励信息的人。

我刚刚在使用 Laravel Sanctum 时遇到了这个错误,看起来好像没有正确设置中间件。 Sanctum 使用 auth:sanctum 中间件作为守卫,这是 Laravel 默认使用的 auth 守卫的某种扩展,但会话由 web 中间件组处理。

我无法准确描述一些 Laravel 内部的东西;目前我在 javascript 方面的经验比 PHP 更丰富。

在我的api.php 文件中,我有登录/注册/注销路由,在我的Kernel.php 文件中,我将\Illuminate\Session\Middleware\StartSession::class, 从 web 组复制到了 api 组。

我必须这样做来修复我的登录单元测试,该测试引发了关于“会话存储未按请求”的错误。复制它让我的postJson 请求可以在单元测试中工作,但过了一段时间,我开始看到 JavaScript 应用程序发布 419 CSRF 错误(这很糟糕,因为它之前运行良好)。

我开始在 /storage/framework/sessions 文件夹中寻找一些文件系统权限,但问题不在于(对我而言)。

我后来发现,对于 Laravel Sanctum 和默认的 AuthenticatesUsers 特征,您必须使用 web 保护来进行身份验证,并使用 auth:sanctum 中间件来保护路由。我试图将 api 保护用于身份验证路由,这是我的 AuthenticatesUsers 特征出现 419 错误的核心。

如果有人在 CSRF 工作或应该工作时收到 419,我建议在系统中需要这些工作的所有关键点进行一些 \Log::debug() 调查:

Auth::check()

Auth::user()

Auth::logout()

如果你对这些有奇怪的行为,根据我的观察,你与sessions 相关的配置有问题,或者你与webapi 守卫相关的配置有问题。

守卫与AuthManager 守卫有关,它维护多个请求和多个单元测试的状态。

这是我找到的最好的描述,我花了一个多星期才发现:

Method Illuminate\Auth\RequestGuard::logout does not exist Laravel Passport

作为最后一个随机示例,如果您的会话以某种方式使用来自 web 中间件组的数据生成 CSRF 令牌,而您的路由设置为使用 api,则它们可能会错误地解释收到的 CSRF。

除此之外,打开 Chrome 开发工具并转到“应用程序”选项卡,然后查看 cookie。确保 XSRF-TOKEN cookie 不安全(即:不是 httpOnly)。

这将允许您拥有这样的 Axios 请求拦截器:

import Cookies from 'js-cookie';

axios.interceptors.request.use(async (request) => 
    try 
        const csrf = Cookies.get('XSRF-TOKEN');
        request.withCredentials = true;

        if (csrf) 
            request.headers.common['XSRF-TOKEN'] = csrf;
        

        return request;
     catch (err) 
        throw new Error(`axios# Problem with request during pre-flight phase: $err.`);
    
);

这就是我当前的 Laravel/Vue SPA 是如何成功运行的。

过去,我在这里也使用过这种技术:

app.blade.php(根布局文件,文档头)

<meta name="csrf-token" content=" csrf_token() ">

bootstrap.js(或任何地方)

window.axios = require('axios');

window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

const token = document.head.querySelector('meta[name="csrf-token"]');

if (token) 
    window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
 else 
    console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');

在我看来,大多数问题都源于以下一个或多个文件中的值不正确:

./.env

./config/auth.php

./config/session.php

密切关注诸如 SESSION_DOMAIN、SESSION_LIFETIME 和 SESSION_DRIVER 之类的东西,就像我说的,文件系统权限。

检查您的 nginx access.log 和/或 error.log 文件;它们可能包含提示。

【讨论】:

【参考方案2】:

刚刚在框架回购中发现了您的问题。 这不是 laravel 问题,您的安装缺少存储文件夹的写入权限,因此 laravel 无法写入会话、日志等。

您收到 419 错误,因为您无法写入文件,因此您无法创建会话,因此您无法验证 csrf 令牌。

快速修复:chmod -R 777 storage

正确的解决方法:将您的安装移动到 nginx/apache/您的用户实际可以写入的文件夹。 如果您使用的是 nginx/apache,请将您的应用程序移到那里并授予项目 (chown -R www-data: /path-to-project) 的正确权限 如果您使用的是 php artisan serve,请将其权限更改为您的用户:chown -R $(whoami) /path-to-project

你明白了,让作家写作,你很好。

【讨论】:

我正在使用数据库驱动程序,但仍然有这个问题。【参考方案3】:

运行这个命令 php工匠密钥:生成

【讨论】:

【参考方案4】:

可能您在浏览器地址栏中的域与 domain 配置文件中的 domain 键或 env 文件中的 SESSION_DOMAIN 不匹配。

【讨论】:

【参考方案5】:

我有同样的问题,但我的问题是 https。表单在 http 页面上,但操作在 https 上。结果会话不一样,导致csrf错误。

【讨论】:

【参考方案6】:

我为 staging 和 prod 使用了相同的应用程序名称,作为 prod 的子域。在暂存中更改应用程序名称后,它起作用了

【讨论】:

以上是关于Laravel 419 错误-VerifyCsrfToken 问题的主要内容,如果未能解决你的问题,请参考以下文章

在 laravel 5.7 中偶尔会出现 419 错误

Vue + Laravel sanctum CSRF 令牌不匹配 419 错误

Laravel 7 发布联系表给我错误 419

登录laravel后页面刷新时419页面过期错误

多次尝试后,Laravel 5.5 在 ajax 调用中不断收到 419 发布错误

Laravel 5.6 上的 419 Ajax 错误 - 已编辑