简体   繁体   English

api 端点未在 Sanctum 上进行 CSRF 令牌验证 - CSRF 令牌不匹配

[英]api endpoint not doing CSRF token validation on Sanctum - CSRF Token Mismatch

I am currently learning Laravel (which is not going particularly smoothly) and I have got a couple of routes configured to test authentication using sanctum.我目前正在学习 Laravel(进展不是特别顺利),并且我已经配置了一些路由来使用 sanctum 测试身份验证。

I am building an API only laravel service with the plan that a ReactJS project will utilise the API.我正在构建一个 API 只有 laravel 服务,计划 ReactJS 项目将利用 API。

I am currently though not using ReactJS and using Insomnia REST client to test the API.我目前虽然没有使用 ReactJS 并使用 Insomnia REST 客户端来测试 API。

I have a route for registering a new user, logging and then another route that just returns the authenticated user to prove that the authentication mechanism is working correctly.我有一条用于注册新用户、日志记录的路由,然后是另一条仅返回经过身份验证的用户以证明身份验证机制正常工作的路由。

I don't know too much about CSRF but my understanding is I request a new CSRF token and then for every request to the API this CSRF token is used, so for example when I login and then get the authenticated user from the corresponding route, the CSRF token cookie is also sent, and therefore if a different CSRF token is sent, I should get a token mismatch error.我对 CSRF 了解不多,但我的理解是我请求一个新的 CSRF 令牌,然后对 API 的每个请求都使用这个 CSRF 令牌,所以例如当我登录然后从相应的路由获取经过身份验证的用户时, CSRF 令牌 cookie 也被发送,因此如果发送了不同的 CSRF 令牌,我应该会收到令牌不匹配错误。

I am testing this using Insomnia by sending a request to /sanctum/csrf-cookie which returns me back a 204 and Insomnia sets 3 cookies, one of which being an XSRF-TOKEN which I understand is an encrypted form of the CSRF token.我正在通过向 /sanctum/csrf-cookie 发送请求来使用 Insomnia 对此进行测试,该请求返回 204,Insomnia 设置 3 cookies,其中之一是 XSRF-TOKEN,据我所知是 CSRF 令牌的加密形式。

I then login successfully and then when I call my route to get the authenticated user, I modify or delete the XSRF-TOKEN cookie and send the request, when I would then expect to get an error about the token not matching but this doesn't seem to be the case and I get a valid response back.然后我成功登录,然后当我调用我的路由以获取经过身份验证的用户时,我修改或删除 XSRF-TOKEN cookie 并发送请求,然后我希望收到有关令牌不匹配的错误,但这不会似乎是这样,我得到了有效的回复。

Below is my api.php (I'm grouping various routes into separate PHP files to keep things organised when I come to actually building the API)下面是我的 api.php(我将各种路由分组到单独的 PHP 文件中,以便在我实际构建 API 时使事情井井有条)

Route::prefix('/auth')->group(__DIR__ . '/endpoints/auth.php');

Route::middleware('auth:sanctum')->get('/me', function(){
    //return response(null, 200);
    return auth()->user();
});

In my /endpoints/auth.php I have the following:在我的/endpoints/auth.php中,我有以下内容:

Route::post('/register', [UserController::class, "register"]);

Route::post('/login', [UserController::class, "login"]);

Route::middleware('auth:sanctum')->post('/logout', [UserController::class, 'logout']);

So in the code above, when I send a request to /api/me after changing or deleting my XSRF-TOKEN I would expect the token mismatch but I am actually getting a 200 OK with the authenticated user details.所以在上面的代码中,当我在更改或删除我的 XSRF-TOKEN 后向/api/me发送请求时,我希望令牌不匹配,但实际上我得到了 200 OK 和经过身份验证的用户详细信息。

UPDATE更新

I've managed to make some progress.我已经取得了一些进展。

I've added the following items to the App/Http/Kernel.php under the api array as follows:我已经将以下项目添加到 api 数组下的 App/Http/Kernel.php 中,如下所示:

'api' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\Session\Middleware\AuthenticateSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
            'throttle:api',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],

When I attempt to submit the login request I now get an HTTP 419 with the error CSRF token mismatch.当我尝试提交登录请求时,我现在收到 HTTP 419,错误为 CSRF 令牌不匹配。

So I've made progress that it now seems to be attempting the CSRF validation, but now it always says there's a mismatch even though its sending the same XSRF-TOKEN cookie in the request.所以我取得了进展,它现在似乎正在尝试 CSRF 验证,但现在它总是说存在不匹配,即使它在请求中发送相同的 XSRF-TOKEN cookie。

I believe I have figured it out, it was partly to do with my HTTP Rest client ( Insomnia.Rest ) but I set up a test project using axios on ReactJS and was having the same issue but then resolved it.我相信我已经弄清楚了,这部分与我的HTTP Rest 客户端 ( Insomnia.Rest ) 有关,但我在ReactJS上使用 axios 设置了一个测试项目,但遇到了同样的问题,但后来解决了。

Part of it was because Sanctums default configuration is a bit all of over the place, part of it was encrypting session/cookies and the other part wasn't.部分原因是Sanctums的默认配置有点乱,部分原因是加密session/cookies ,而另一部分则不是。

So under config/session.php set encrypt => true所以在config/session.php下设置encrypt => true

Under App\Http\Kernel.php add the following to the api middlewareGroupsApp\Http\Kernel.php下,将以下内容添加到 api 中间件组

\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,

Under confif/cors.php set support_credentials => trueconfif/cors.php下设置support_credentials => true

Under config/session.php ensure SESSION_DRIVER is cookieconfig/session.php下确保SESSION_DRIVER是 cookie

The other problem was a misunderstanding of what gets sent in the request.另一个问题是对请求中发送的内容的误解。

When you get the XSRF-TOKEN when calling /sanctum/csrf-cookie I assumed that is just sent back in the request as a cookie which Insomnia automatically does.当您在调用/sanctum/csrf-cookie时获得XSRF-TOKEN时,我假设它只是作为 Insomnia 自动执行的 cookie 在请求中发回。

This is not the case.不是这种情况。 Instead, you should extract the cookie from the Insomnia request, and then in each POST/PUT/DELETE request add a new header called X-XSRF-TOKEN to the value of what the cookie was from the sanctum GET request.相反,您应该从 Insomnia 请求中提取 cookie,然后在每个POST/PUT/DELETE请求中添加一个名为X-XSRF-TOKEN的新 header 到来自sanctum GET 请求的 cookie 的值。

If you are using an HTTP client for your frontend project such as AXIOS this is done automatically so you don't need to worry about that.如果您为前端项目使用HTTP客户端,例如 AXIOS,这是自动完成的,因此您无需担心。

The next issue was with Insomnia.Rest HTTP client I was using.下一个问题是我使用的Insomnia.Rest HTTP 客户端。

When I received the XSRF-TOKEN Insomnia stores the cookie inside it cookie store, however, they seem to encode it incorrectly so you get a cookie string stored as follows:当我收到XSRF-TOKEN Insomnia 时,Insomnia 将 cookie 存储在它的 cookie 存储区中,但是,它们似乎对其编码不正确,因此您会得到一个存储如下的 cookie 字符串:

eyJpdiI6Iml5YWEreGVaYUw0WGc2QmxlVEhQOGc9PSIsInZhbHVlIjoieVU2bmdyTjMyNFM0d0dnb3RsM24rMDFhRnJNWHVLcGg2SU9YMHh5dW8yaTZSTWcxbGxtSFdaK0I5MzB4Ymc4QWZWSzhjN2R6Y1RUTTc0d1VIY2FUaVhGMVE4bzQvWVBmL1YvajAwY3ZUNlZ4VEZIRk12cloyV0owVmNYOUxEZTIiLCJtYWMiOiI4OTUyN2U1MGI3NmUyMjEzZjgyNDcxMjAwYmViYjRkNzAwYmQ1YWUxOGY5NTYyNTVhZDczMmQ0ZjdlNjQwMGFhIn0%3D eyJpdiI6Iml5YWEreGVaYUw0WGc2QmxlVEhQOGc9PSIsInZhbHVlIjoieVU2bmdyTjMyNFM0d0dnb3RsM24rMDFhRnJNWHVLcGg2SU9YMHh5dW8yaTZSTWcxbGxtSFdaK0I5MzB4Ymc4QWZWSzhjN2R6Y1RUTTc0d1VIY2FUaVhGMVE4bzQvWVBmL1YvajAwY3ZUNlZ4VEZIRk12cloyV0owVmNYOUxEZTIiLCJtYWMiOiI4OTUyN2U1MGI3NmUyMjEzZjgyNDcxMjAwYmViYjRkNzAwYmQ1YWUxOGY5NTYyNTVhZDczMmQ0ZjdlNjQwMGFhIn0%3D

Note at the end it has %3D, this is a URL encoding for the = sign so therefore Laravel gets this and can't match with what it was expecting.请注意最后它有 %3D,这是 = 符号的 URL 编码,因此 Laravel 得到这个并且无法与它期望的相匹配。

Therefore you need to edit the cookie to replace %3D to be = and then send the request and it should work.因此,您需要编辑 cookie 以将 %3D 替换为 =,然后发送请求,它应该可以工作。

I have one other strange thing though is that if I send the request with a Referrer and Origin header, the CSRF validation works, however, if I don't then the request is accepted which doesn't seem right to me as it kind of defeats the purpose of the CSRF protection.我还有另一件奇怪的事情是,如果我发送带有引荐来源网址和来源 header 的请求,CSRF 验证有效,但是,如果我不这样做,那么请求将被接受,这对我来说似乎不正确,因为它有点违背了 CSRF 保护的目的。

I also faced this error.我也遇到了这个错误。 I add this code on .env file and error is gone.我将此代码添加到.env文件中,错误消失了。

SESSION_DOMAIN=localhost
SANCTUM_STATEFUL_DOMAINS=localhost

I had the same issue, tried to add the code below to.env我有同样的问题,试图将下面的代码添加到.env

SESSION_DOMAIN=localhost
SANCTUM_STATEFUL_DOMAINS=localhost

But it did not work however, changing localhost to 127.0.0.1 as below worked for me.但是它没有用,如下所示将 localhost 更改为 127.0.0.1 对我有用。

SESSION_DOMAIN=127.0.0.1
SANCTUM_STATEFUL_DOMAINS=127.0.0.1

You don't get a token mismatch with /api/me because this is a GET request, and CSRF protection is for endpoints that might perform an unauthorized command.您不会得到与/api/me不匹配的令牌,因为这是一个 GET 请求,而 CSRF 保护是针对可能执行未经授权命令的端点。

I think you might not (yet) grasp what CSRF is and what CRSF protection is supposed to do.我认为您可能(还)不了解什么是 CSRF 以及 CRSF 保护应该做什么。

Here, just listing the user is not an unauthorized command;在这里,仅列出用户并不是未经授权的命令; you can request it over and over again and nothing else happens.您可以一遍又一遍地请求它,没有其他任何反应。 It does not change anything in a database, do a money transfer, reset a password or anything else.它不会更改数据库中的任何内容、进行汇款、重置密码或其他任何操作。

Does that help think about why requesting any GET or HEAD does not involve CSRF checks?这是否有助于思考为什么请求任何 GET 或 HEAD 不涉及 CSRF 检查?

Just requesting that URI itself shouldn't perform an unwanted command for an authorized user;只是请求 URI 本身不应该为授权用户执行不需要的命令; traditionally only POST and others are acceptable for running some command on a Web application, API or not;传统上只有 POST 和其他可以在 Web 应用程序上运行某些命令,API 或不是; there are a number of reasons why having all the parameters in a GET request is unacceptable, and the main one is leakage of potentially sensitive information.将所有参数都包含在 GET 请求中是不可接受的,原因有很多,其中最主要的一个是潜在敏感信息的泄漏。

If you check the documentation, it explicitly mentions that only POST, PUT, PATCH and DELETE are checked for the secret session value.如果您查看文档,它明确提到仅检查 POST、PUT、PATCH 和 DELETE 的秘密值 session。 The reasons why might need a bit more further reading.为什么可能需要进一步阅读的原因。

[1] https://laravel.com/docs/8.x/csrf [1] https://laravel.com/docs/8.x/csrf

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM