Laravel DecryptException -负载无效

qv7cva1a  于 2023-03-09  发布在  其他
关注(0)|答案(7)|浏览(147)

我正在将 AJAX 发布请求发送回我的Laravel API,并收到此错误消息:

在compiled.php第13235行出现解密异常:有效负载无效。

我从cookie中阅读XSRF-TOKEN,并将其作为名为X-XSRF-TOKEN的请求头发送沿着。
该网站是一个完全独立于Laravel API的网站,但共享相同的会话,这就是为什么我从cookie中获取值。
奇怪的是,偶尔也会管用。知道是什么原因吗?

xriantvc

xriantvc1#

如果你用JavaScript发送X-XSRF-TOKEN,你可以用decodeURIComponent()解码,它会把%3D转换成=

dl5txlt9

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;
            }
2lpgd968

2lpgd9683#

我有同样的问题,这确实是由于cookie被url编码,而不是由laravel正确解码
您可以通过在解密之前对cookie进行url解码来解决这个问题
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并用新类替换它
例如:

protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
    //...
but5z9lq

but5z9lq4#

它也可能发生,因为加密/解密错误,其中来自数据库的纯文本被解密方法/函数解密,因为你会直接添加一些数据到数据库中,需要加密bot插入作为纯文本,所以它可能与加密/解密问题有关。

jaql4c8m

jaql4c8m5#

+1到Tofandel的答案,我删除了'XSRF-TOKEN' cookie的加密.
app/Http/Middleware/EncryptCookies.php中添加:

protected $except = [
   'XSRF-TOKEN',
];
u0sqgete

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语句总是成功。这似乎与我的请求头中的数据量有关,但问题是不确定的。

jpfvwuh4

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

相关问题