Viewed   195 times

Can the TokenMismatchException be catched using try catch block? Instead of displaying the debug page that shows the "TokenMismatchException in VerifyCsrfToken.php line 46...", I want it to display the actual page and just display an error message.

I have no problems with the CSRF, I just want it to still display the page instead of the debug page.

To replicate (using firefox): Steps:

  1. Open page (http://example.com/login)
  2. Clear Cookies (Domain, Path, Session). I am using web developer toolbar plugin here.
  3. Submit form.

Actual Results: "Whoops, looks like something went wrong" page displays. Expected Results: Still display the login page then pass an error of "Token mismatch" or something.

Notice that when I cleared the cookies, I didn't refresh the page in order for the token to generate a new key and force it to error out.

UPDATE (ADDED FORM):

        <form class="form-horizontal" action="<?php echo route($formActionStoreUrl); ?>" method="post">
        <input type="hidden" name="_token" value="<?php echo csrf_token(); ?>" />
        <div class="form-group">
            <label for="txtCode" class="col-sm-1 control-label">Code</label>
            <div class="col-sm-11">
                <input type="text" name="txtCode" id="txtCode" class="form-control" placeholder="Code" />
            </div>
        </div>
        <div class="form-group">
            <label for="txtDesc" class="col-sm-1 control-label">Description</label>
            <div class="col-sm-11">
                <input type="text" name="txtDesc" id="txtDesc" class="form-control" placeholder="Description" />
            </div>
        </div>
        <div class="form-group">
            <label for="cbxInactive" class="col-sm-1 control-label">Inactive</label>
            <div class="col-sm-11">
                <div class="checkbox">
                    <label>
                        <input type="checkbox" name="cbxInactive" id="cbxInactive" value="inactive" />&nbsp;
                        <span class="check"></span>
                    </label>
                </div>
            </div>
        </div>
        <div class="form-group">
            <div class="col-sm-12">
                <button type="submit" class="btn btn-primary pull-right"><i class="fa fa-save fa-lg"></i> Save</button>
            </div>
        </div>
    </form>

Nothing really fancy here. Just an ordinary form. Like what I've said, the form is WORKING perfectly fine. It is just when I stated the above steps, it errors out due to the TOKEN being expired. My question is that, should the form behave that way? I mean, when ever I clear cookies and session I need to reload the page too? Is that how CSRF works here?

 Answers

3

You can handle TokenMismatchException Exception in AppExceptionsHandler.php

<?php namespace AppExceptions;
use Exception;
use IlluminateFoundationExceptionsHandler as ExceptionHandler;
use IlluminateSessionTokenMismatchException;


class Handler extends ExceptionHandler {


    /**
     * A list of the exception types that should not be reported.
     *
     * @var array
     */
    protected $dontReport = [
        'SymfonyComponentHttpKernelExceptionHttpException'
    ];
    /**
     * Report or log an exception.
     *
     * This is a great spot to send exceptions to Sentry, Bugsnag, etc.
     *
     * @param  Exception  $e
     * @return void
     */
    public function report(Exception $e)
    {
        return parent::report($e);
    }
    /**
     * Render an exception into an HTTP response.
     *
     * @param  IlluminateHttpRequest  $request
     * @param  Exception  $e
     * @return IlluminateHttpResponse
     */
    public function render($request, Exception $e)
    {
        if ($e instanceof TokenMismatchException){
            // Redirect to a form. Here is an example of how I handle mine
            return redirect($request->fullUrl())->with('csrf_error',"Oops! Seems you couldn't submit form for a long time. Please try again.");
        }

        return parent::render($request, $e);
    }
}
Thursday, October 20, 2022
4

When I realized this was only happening in IE and Chrome, but not Firefox, it led me to the fix. The app was using AddThis share buttons and the javascript was adding an iframe to the pages. This issue is resolved by adding a P3P header to the VerifyCsrfToken Middleware. Hope this saves somebody the hours I lost.

public function handle($request, Closure $next)
    {
        $response = $next($request);

        if (last(explode('\',get_class($response))) != 'RedirectResponse') {
            $response->header('P3P', 'CP="IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT"');
        }

        return $response;
    }
Monday, August 8, 2022
 
2

you need to put all jobs

$schedule->job(new Job1)->everyMinute(); 
$schedule->job(new Job2)->everyMinute(); 
$schedule->job(new Job3)->everyMinute(); 

under schedule() function in kernel.php and than scheduler will handle all the jobs.

Friday, December 9, 2022
 
2

Generally API's are used for cross site requests. So your CSRF protection is pointless.

If you're not gonna use it cross-site, chances are that an API is not the optimal solution for what you're trying to do. Anyway, you could make an API endpoint which returns a token.

public function getToken(){
    return Response::json(['token'=>csrf_token()]);
}

If you want to disable CSRF-protection on some methods, you could use except or only.

$this->beforeFilter('csrf', array('on' => 'post', 
                                 'except'=>array('methodName', 'anotherMethod')
                                  ));

Please refer to the official Laravel documentation.

Sunday, September 18, 2022
 
sara
 
4

Possible Change - 1

Setup Token on Header

Set the token on <head> of your default.blade.php view

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

Add ajaxSetup on the top of your script, that will be accessible to everywhere. This will set headers on each ajax call

$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    }
});

Set Token on <form> tag

Add below function to your <form> tag. This function will generate a hidden field named _token and filled value with token

{{csrf_field()}}

Add csrf_token() function to your hidden _token in value attribute. This will generate only encrypted string.

<input type="hidden" name="_token" value="{{csrf_token()}}"/>.


Possible Change - 2

Check session storage path & Permission

Here assume that project app url is APP_URL=http://project.dev/ts/toys-store

  1. Set the write permission to storage_path('framework/sessions')
  2. Check the path of your laravel project 'path' => '/ts/toys-store', this path is root of your laravel project.
  3. Change the name of your cookie 'cookie' => 'toys-store',

    return [
        'driver' => env('SESSION_DRIVER', 'file'),
        'lifetime' => 120,
        'expire_on_close' => false,
        'encrypt' => false,
        'files' => storage_path('framework/sessions'),
        'connection' => null,
        'table' => 'sessions',
        'lottery' => [2, 100],
        'cookie' => 'toys-store',
        'path' => '/ts/toys-store',
        'domain' => null,
        'secure' => false,
        'http_only' => true,
    ];
    

Possible Change - 3

Use _token field on AJAX

There are many ways to send _token on AJAX call

  1. Get all input field's value within <form> tag using var formData = new FormData($("#cart-add")[0]);
  2. Use $("#cart-add").serialize(); or $("#cart-add").serializeArray();
  3. Add _token manually on data of AJAX. using $('meta[name="csrf-token"]').attr('content') or $('input[name="_token"]').val().
  4. We can set as header on a particular ajax call like below code.

    $.ajax({
        url: "path/to/ajax",
        type: "POST",
        data: formData,
        processData: false,
        contentType: false,
        dataType: "json",
        headers: {
            'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
        }
    });
    
Sunday, September 25, 2022
 
ibug
 
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :