5

I have a working form:

    {!! Form::open() !!}
            <div class="form-group">
                <label for="name">Name</label>
                <input type="text" class="form-control" id="name" placeholder="Name">
            </div>
            <div class="form-group">
                <label for="division">Division</label>
                <input type="text" class="form-control" id="division" placeholder="Division">
            </div>
        {!! Form::submit('send', array('class'=>'btn btn-success pull-right')) !!}
    {!! Form::close() !!}

This works as a standalone page submitting and storing the inputs. Now I need to put this in an iframe so it can be called from another website. When I do this with:

<iframe src="http://1.1.1.1/register_user" style="width:600px;height:500px;"></iframe>

The form displays but when the user submits they get the following:

TokenMismatchException in VerifyCsrfToken.php line 53:
1. in VerifyCsrfToken.php line 53
2. at VerifyCsrfToken->handle(object(Request), object(Closure))
3. at call_user_func_array(array(object(VerifyCsrfToken), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 124
4. at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in ShareErrorsFromSession.php line 54
5. at ShareErrorsFromSession->handle(object(Request), object(Closure))
6. at call_user_func_array(array(object(ShareErrorsFromSession), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 124
7. at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in StartSession.php line 62
8. at StartSession->handle(object(Request), object(Closure))
9. at call_user_func_array(array(object(StartSession), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 124
10. at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in AddQueuedCookiesToResponse.php line 37
11. at AddQueuedCookiesToResponse->handle(object(Request), object(Closure))
12. at call_user_func_array(array(object(AddQueuedCookiesToResponse), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 124
13. at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in EncryptCookies.php line 59
14. at EncryptCookies->handle(object(Request), object(Closure))
15. at call_user_func_array(array(object(EncryptCookies), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 124
16. at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in CheckForMaintenanceMode.php line 42
17. at CheckForMaintenanceMode->handle(object(Request), object(Closure))
18. at call_user_func_array(array(object(CheckForMaintenanceMode), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 124
19. at Pipeline->Illuminate\Pipeline\{closure}(object(Request))
20. at call_user_func(object(Closure), object(Request)) in Pipeline.php line 103
21. at Pipeline->then(object(Closure)) in Kernel.php line 122
22. at Kernel->sendRequestThroughRouter(object(Request)) in Kernel.php line 87
23. at Kernel->handle(object(Request)) in index.php line 54

This is what I see in the logs:

[2015-08-10 00:52:21] production.ERROR: exception
'Illuminate\Session\TokenMismatchException' in /home/forge/default/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php:53
Stack trace:
#0 [internal function]: Illuminate\Foundation\Http\Middleware\VerifyCsrfToken->handle(Object(Illuminate\Http\Request), Object(Closure))
#1 /home/forge/default/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(124): call_user_func_array(Array, Array)
#2 /home/forge/default/vendor/laravel/framework/src/Illuminate/View/Middleware/ShareErrorsFromSession.php(54): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#3 [internal function]: Illuminate\View\Middleware\ShareErrorsFromSession->handle(Object(Illuminate\Http\Request), Object(Closure))
#4 /home/forge/default/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(124): call_user_func_array(Array, Array)
#5 /home/forge/default/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(62): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#6 [internal function]: Illuminate\Session\Middleware\StartSession->handle(Object(Illuminate\Http\Request), Object(Closure))
#7 /home/forge/default/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(124): call_user_func_array(Array, Array)
#8 /home/forge/default/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse.php(37): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#9 [internal function]: Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse->handle(Object(Illuminate\Http\Request), Object(Closure))
#10 /home/forge/default/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(124): call_user_func_array(Array, Array)
#11 /home/forge/default/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/EncryptCookies.php(59): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#12 [internal function]: Illuminate\Cookie\Middleware\EncryptCookies->handle(Object(Illuminate\Http\Request), Object(Closure))
#13 /home/forge/default/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(124): call_user_func_array(Array, Array)
#14 /home/forge/default/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(42): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#15 [internal function]: Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode->handle(Object(Illuminate\Http\Request), Object(Closure))
#16 /home/forge/default/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(124): call_user_func_array(Array, Array)
#17 [internal function]: Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#18 /home/forge/default/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(103): call_user_func(Object(Closure), Object(Illuminate\Http\Request))
#19 /home/forge/default/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(122): Illuminate\Pipeline\Pipeline->then(Object(Closure))
#20 /home/forge/default/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(87): Illuminate\Foundation\Http\Kernel->sendRequestThroughRouter(Object(Illuminate\Http\Request))
#21 /home/forge/default/public/index.php(54): Illuminate\Foundation\Http\Kernel->handle(Object(Illuminate\Http\Request))
#22 {main}  

What am I doing wrong to cause the mismatch in the iframe and how do I fix it?

neil
  • 161
  • 4
  • 12
  • Laravel 5 expects you to pass a CSRF token with all form data to ensure it was submitted from a trusted source. The error you are getting is because the Token was not included or did not match the expected value. – Jeemusu Aug 10 '15 at 01:27

2 Answers2

6

Laravel 5 has a global middleware enabled called VeryifyCsrfToken that checks all POST requests for a token to apply Cross-site request forgery protection.

Cross-site request forgeries are a type of malicious exploit whereby unauthorized commands are performed on behalf of the authenticated user.

Allowing users to submit your form from an iframe on a different domain is exactly the kind of thing Laravels CSRF protection is trying to prevent.

There is a way to disable CSRF verification for certain URL's. You can add a new item to the $except array to exclude that url from CSRF verification.

Http/Middleware/VerifyCsrfToken.php

<?php

namespace App\Http\Middleware;

use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;

class VerifyCsrfToken extends BaseVerifier
{
    /**
     * The URIs that should be excluded from CSRF verification.
     *
     * @var array
     */
    protected $except = [
        'your/uri'
    ];
}
Jeemusu
  • 10,415
  • 3
  • 42
  • 64
  • I add in the domains like so: protect $except = [ 'http:some domain.com/form_page.html' ]; but I am still getting the same error. Is this the correct way to add in the domain? – neil Aug 10 '15 at 01:46
  • Sorry, I should of been more clear. You don't add the domain, you add the url that you want to disable CSRF protection for on your application. This should be the same URL your form is posting to. Also, you need to be aware that by doing so, you are opening your application up to CSRF attacks via this url. – Jeemusu Aug 10 '15 at 01:53
0

@Jeemusu 's answers provides a solution, though a few comments and another suggested solution after reading: https://discussions.apple.com/thread/4156939?tstart=0

  • To me, this has nothing with preventing CSRF, other browsers are not preventing this, I would say that this is more related with preventing tracking.
  • The page at Apple suggests the following: the problem only occures when the iframe domain has not been visited first (and this is what I have observed).
  • One solution would be for the caller domain to set a cookie when a user arrives, redirect to the called domain to "count as a visit" and then redirect back to the called domain (that would read the first set cookies to not redirect again).

I would say that disabling CSRF protection is an unsecure idea.

AsTeR
  • 7,247
  • 14
  • 60
  • 99