Laravel TokenMismatchException database session

2019-01-20 15:46发布

My $request->input(_token) is a mismatch of $request->session()->toke() when switching from file to database sessions.

This is causing a CSRF TokenMismatchException. When switching back from database to file sessons driver the mismatch does not occur.

Does anyone know why i get this mismatch and possibly how to resolve it? :) What i have done:


Using Laravel 5.0
PHP 5.6.30

php artisan session:table : Created Laravel session table composer dump-autoload php artisan config:clear php arisan config:cache

My session.php config looks like this:

return [

    'driver' => 'database',
    'lifetime' => 120,
    'expire_on_close' => false,
    'encrypt' => false,
    'files' => storage_path().'/framework/sessions',
    'connection' => null,
    'table' => 'laravel_session',
    'lottery' => [2, 100],
    'cookie' => 'laravel_session',
    'path' => '/',
    'domain' => null,
    'secure' => false,

];

VerifyCsrfToken Illuminate\Foundation\Middleware

protected function tokensMatch($request)
{
    $tok =  $request->input('_token') ; //4ExGXl9mRM75d7brfQhgIWcQzsSVjnUHDoDcKJxp
    $tokhead  = $request->header('X-CSRF-TOKEN'); 
    $sessToken = $request->session()->token();//57DLb3uTs8brVPKpBxor14Hg0ZvQPpYW3flktP86

    $token = $request->input('_token') ?: $request->header('X-CSRF-TOKEN');

    if ( ! $token && $header = $request->header('X-XSRF-TOKEN'))
    {
        $token = $this->encrypter->decrypt($header);
    }

    return StringUtils::equals($request->session()->token(), $token);

Database table is populated with data after switching to database sesseio driver:

SELECT id, payload, last_activity, user_id FROM kartserver_2.laravel_session;

d33d5782e1eed56771baa56f9410a24b9e628ff6    YToxNzp7czo2OiJfdG9rZW4iO3M6NDA6Ikh6dUc4WG1PUDFZalRHY0QwcW5QZzlFSGRUSkJ3ZmVOUkVjM0RJVk0iO3M6NToiZmxhc2giO2E6Mjp7czozOiJvbGQiO2E6MDp7fXM6MzoibmV3IjthOjA6e319czoyMDoicGFzc3dvcmRSZXF1aXJlbWVudHMiO086NDE6Ikhhd2tTb2Z0d2FyZVxTZWN1cml0eVxQYXNzd29yZFJlcXVpcmVtZW...   1487315670  1862

I am generating csrf_tokens in html

<input type="hidden" name="_token" id="_token" value="{!! csrf_token() !!}">

2条回答
放我归山
2楼-- · 2019-01-20 16:14

If you are using Laravel 5.4* and you happen to stumble upon this problem, here is what you need to do

1- Update your .env file

# file = .env in your project root

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=testdb
DB_USERNAME=db_user
DB_PASSWORD=secret_pass

SESSION_DRIVER=database

Note the DB_CONNECTION setting here that you will need in next step.

2- update config/session.php file Where connection param should hold the string you used for DB_CONNECTION in .env file

# file = config/session.php

'driver' => env('SESSION_DRIVER', 'database'),
'connection' => 'mysql', // this is from DB_CONNECTION in .env file 

3- generate sessions table

php artisan session:table
// run the migration !!! very very important
php artisan migrate

4- if for some reason you decided to create the table manually without using migration , use this SQL. This is very important step, a wrong table will result in all kinds of problems. Primarily do not make the mistake of creating a table manually with id column as bigint as usual, session table is different.

SQL for sessions table that you should run if you wanna create manually

DROP TABLE IF EXISTS `sessions`;
create table sessions
(
  id varchar(255) not null,
  user_id int(10) unsigned null,
  ip_address varchar(45) null,
  user_agent text null,
  payload text not null,
  last_activity int not null,
  constraint sessions_id_unique
  unique (id)
)

That should solve the token mismatch exception after setting db as session save path.

查看更多
霸刀☆藐视天下
3楼-- · 2019-01-20 16:22

They are supposed to be different :)

  • A csrf token is a way to prevent csrf attacks. This is a form of attack that shows up like in this example:

You have a GET /pay50dollarToHarry (very stupid example) endpoint that is triggered on visit. When goes to a forum like stackoverflow and posts an image like:

<img src="youdomain.com/pay50dollarToHarry />

The browser will visit that link to get the image and will transfer the 50 dollars. By using csrf tokens inside your form, this cannot be done from other pages.

  • A session token serves the purpose of keeping track of a user across multiple pages of your website.

P.S. Please do not alter code inside the framework / libraries: they will be overwritten on update. It's bad practise. the original function:

/**
     * Determine if the session and input CSRF tokens match.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return bool
     */
    protected function tokensMatch($request)
    {
        $token = $this->getTokenFromRequest($request);
        return is_string($request->session()->token()) &&
               is_string($token) &&
               hash_equals($request->session()->token(), $token);
    }
查看更多
登录 后发表回答