Laravel DecryptException - 有效负载无效

时间:2017-06-20 11:46:05

标签: php laravel api cookies

我正在向我的Laravel API发送一个AJAX帖子请求并收到此错误消息:

在compile.php第13235行中的DecryptException: 有效负载无效。

我正在从cookie中读取XSRF-TOKEN并将其作为名为X-XSRF-TOKEN的请求头发送。

该网站是Laravel API中完全独立的网站,但共享相同的会话,这就是我从cookie中获取价值的原因。

奇怪的是,它偶尔会起作用。是什么原因引起了这个?

7 个答案:

答案 0 :(得分:6)

如果您从JavaScript发送X-XSRF-TOKEN,则可以使用decodeURIComponent()对其进行解码。它会将%3D转换为=

答案 1 :(得分:3)

我发现了问题的原因。 XSRF-TOKEN cookie值有时会在末尾附加一个流氓字符:'%3D' - 有时最后有两个。不知道他们是如何到达那里的,但是当它们出现时,验证失败了。

如果您对cookie值进行base64_decode,则会得到一个具有流氓字符的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;
            }

答案 2 :(得分:1)

它也可能由于加密/解密错误而发生,在这种情况下,数据库中的纯文本通过解密方法/功能进行了解密,因为您可能已经直接向数据库中添加了一些数据,需要将其作为明文插入,因此可能与加密/解密问题有关。

答案 3 :(得分:1)

我遇到了同样的问题,这确实是由于cookie被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 is_array($cookie)
                        ? $this->decryptArray($cookie)
                        : $this->encrypter->decrypt(urldecode($cookie), static::serialized($name));
    }
}

确保在app/Http/Kernel.php中使用正确的中间件,应该寻找EncryptCookies并将其替换为新类

例如:

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

答案 4 :(得分:0)

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

答案 5 :(得分:0)

这是在Laravel中对我有用的解决方案和步骤:

  1. 在文档标题中将CSRF令牌作为名为 csrf-token 的元标记:

<!-- CSRF Token -->
 <meta name="csrf-token" content="{{ csrf_token() }}">

  1. 创建一个JavaScript函数以检索csrf-token元标记的值:

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

答案 6 :(得分:0)

+1 Tofandel 的回答,我删除了 app/Http/Middleware/EncryptCookies.php cookie 的加密。

protected $except = [ 'XSRF-TOKEN', ]; 中添加:

{{1}}