我正在将 AJAX 发布请求发送回我的Laravel API,并收到此错误消息:
在compiled.php第13235行出现解密异常:有效负载无效。
我从cookie中阅读XSRF-TOKEN,并将其作为名为X-XSRF-TOKEN的请求头发送沿着。该网站是一个完全独立于Laravel API的网站,但共享相同的会话,这就是为什么我从cookie中获取值。奇怪的是,偶尔也会管用。知道是什么原因吗?
xriantvc1#
如果你用JavaScript发送X-XSRF-TOKEN,你可以用decodeURIComponent()解码,它会把%3D转换成=。
X-XSRF-TOKEN
decodeURIComponent()
%3D
=
dl5txlt92#
我发现了问题的原因,XSRF-TOKEN cookie值的末尾有时会附加一个流氓字符:“%3D”-有时末尾有两个这样的字符串。不知道它们是如何到达的,但当它们出现时,验证失败。如果您base64_decode cookie值,您会得到一个json字符串,其中包含流氓字符:“7”追加到末尾,因此Laravel的解密方法失败。最后我不得不编写自己的CSRF验证函数:
$payload = base64_decode($request->header('X-XSRF-TOKEN')); //Remove any rogue chars from the end of the json for($i=0; $i<strlen($payload); $i++){ $lastChar = substr($payload, -1); if($lastChar != '}'){ $payload = substr($payload, 0, -1); } else { break; } } //Needs to be base64 encoded when passed to decrypt $payload = base64_encode($payload); $headerToken = decrypt($payload); $cookieToken = $request->cookie('XSRF-TOKEN'); //Compare tokens if($headerToken == $cookieToken){ return true; } else { return false; }
2lpgd9683#
我有同样的问题,这确实是由于cookie被url编码,而不是由laravel正确解码您可以通过在解密之前对cookie进行url解码来解决这个问题在app/Http/Middleware/EncryptCookies.php中
app/Http/Middleware/EncryptCookies.php
<?php namespace App\Http\Middleware; use Illuminate\Cookie\Middleware\EncryptCookies as Middleware; class EncryptCookies extends Middleware { /** * Decrypt the given cookie and return the value. * * @param string $name * @param string|array $cookie * @return string|array */ protected function decryptCookie($name, $cookie) { return parent::decryptCookie($name, is_array($cookie) ? $cookie : urldecode($cookie)); } }
确保您在app/Http/Kernel.php中使用了正确的中间件,您应该查找EncryptCookies并用新类替换它例如:
app/Http/Kernel.php
EncryptCookies
protected $middlewareGroups = [ 'web' => [ \App\Http\Middleware\EncryptCookies::class, //...
but5z9lq4#
它也可能发生,因为加密/解密错误,其中来自数据库的纯文本被解密方法/函数解密,因为你会直接添加一些数据到数据库中,需要加密bot插入作为纯文本,所以它可能与加密/解密问题有关。
jaql4c8m5#
+1到Tofandel的答案,我删除了'XSRF-TOKEN' cookie的加密.在app/Http/Middleware/EncryptCookies.php中添加:
'XSRF-TOKEN'
protected $except = [ 'XSRF-TOKEN', ];
u0sqgete6#
我也遇到过类似的问题,但似乎只与Google Chrome有关。每当遇到解密异常时,我就将EncryptCookies修改为dd():
protected function decrypt(Request $request) { foreach ($request->cookies as $key => $c) { if ($this->isDisabled($key)) { continue; } try { $request->cookies->set($key, $this->decryptCookie($c)); } catch (DecryptException $e) { dd('exception: ', $e, $key, $c, $request); // added by me $request->cookies->set($key, null); } } return $request; }
奇怪的是,每当我刷新页面时,有时会抛出DecryptException,但大多数情况下try语句会成功。当我在IE和Firefox中测试时,try语句总是成功。这似乎与我的请求头中的数据量有关,但问题是不确定的。
jpfvwuh47#
下面是一个解决方案和步骤,为我在Laravel工作:1.将CSRF标记作为名为 csrf-token 的 meta标记包含在文档的标题中:
<!-- CSRF Token --> <meta name="csrf-token" content="{{ csrf_token() }}">
1.创建一个JavaScript函数来检索csrf-token meta标记的值:
function csrf(name="csrf-token"){ const metas = document.getElementsByTagName('meta'); for (let i = 0; i < metas.length; i++) { if (metas[i].getAttribute('name') === name) { return metas[i].getAttribute('content'); } } return null; }
1.设置请求的X-CSRF-TOKEN头,并将csrf()函数的值赋给它。使用Fetch API的示例:
let params = {headers:{}}; params.headers["Content-Type"] = "application/json; charset=UTF-8"; params.headers["X-CSRF-TOKEN"] = csrf(); // call your csrf() function params.mode = "same-origin"; params.method = "POST"; let response = await fetch('/your-url', params); // handle the response object
7条答案
按热度按时间xriantvc1#
如果你用JavaScript发送
X-XSRF-TOKEN
,你可以用decodeURIComponent()
解码,它会把%3D
转换成=
。dl5txlt92#
我发现了问题的原因,XSRF-TOKEN cookie值的末尾有时会附加一个流氓字符:“%3D”-有时末尾有两个这样的字符串。不知道它们是如何到达的,但当它们出现时,验证失败。
如果您base64_decode cookie值,您会得到一个json字符串,其中包含流氓字符:“7”追加到末尾,因此Laravel的解密方法失败。
最后我不得不编写自己的CSRF验证函数:
2lpgd9683#
我有同样的问题,这确实是由于cookie被url编码,而不是由laravel正确解码
您可以通过在解密之前对cookie进行url解码来解决这个问题
在
app/Http/Middleware/EncryptCookies.php
中确保您在
app/Http/Kernel.php
中使用了正确的中间件,您应该查找EncryptCookies
并用新类替换它例如:
but5z9lq4#
它也可能发生,因为加密/解密错误,其中来自数据库的纯文本被解密方法/函数解密,因为你会直接添加一些数据到数据库中,需要加密bot插入作为纯文本,所以它可能与加密/解密问题有关。
jaql4c8m5#
+1到Tofandel的答案,我删除了
'XSRF-TOKEN'
cookie的加密.在
app/Http/Middleware/EncryptCookies.php
中添加:u0sqgete6#
我也遇到过类似的问题,但似乎只与Google Chrome有关。每当遇到解密异常时,我就将EncryptCookies修改为dd():
奇怪的是,每当我刷新页面时,有时会抛出DecryptException,但大多数情况下try语句会成功。当我在IE和Firefox中测试时,try语句总是成功。这似乎与我的请求头中的数据量有关,但问题是不确定的。
jpfvwuh47#
下面是一个解决方案和步骤,为我在Laravel工作:
1.将CSRF标记作为名为 csrf-token 的 meta标记包含在文档的标题中:
1.创建一个JavaScript函数来检索csrf-token meta标记的值:
1.设置请求的X-CSRF-TOKEN头,并将csrf()函数的值赋给它。使用Fetch API的示例: