5

Problem scenario:

I'm creating a blog with Laravel 4. The form that's responsible for the creation of new blog posts is secured by the build in CSRF protection (Laravel Docs: CSRF Protection).

Everything works fine so far, but it seems that laravel does not refresh the csrf token on every request.

The problem that occurs is that if the user hits the back button of the browser to return to the submitted form, the entered data persists and the user is able to "re-submit" the form. This might create an open door for spammers.

Usually this is prevented by the CSRF token, as it's being refreshed on every request, but Laravel doesn't seem to do it like that.

I use the laravel "Resource Controller" approach (Laravel Docs: Resource Controllers) to handle the form and blog post views. Furthermore I use Laravels input validator before storing the submitted input in the database (MySQL).


So the following ideas came up:

  1. somehow force Laravel 4 to regenerate the csrf automatically on every request

  2. generate another token and include it into the form manually

  3. save a timestamp of form submition in the users session (php or database) and throttle new form submissions on a time base

Personally I prefer the first idea, but unfortunately I couldn't find a way of forcing laravel to behave how I want it to be, without hacking the "Illuminate" itself (which I want to keep "as is" to be able to update laravel without "hasslehoff" ^^).

What would you recommend?

How did you handle the problem yourself?

ircmaxell
  • 163,128
  • 34
  • 264
  • 314
Markus Hofmann
  • 3,427
  • 4
  • 21
  • 31
  • 1
    I just checked how stackoverflow handles the form on "history.back()": On re-submit of the same data, it says "A question with that title already exists; please be more specific." and "You can only post once every 20 minutes.". Is an option but not really what I want... – Markus Hofmann Jun 21 '13 at 16:10

1 Answers1

20

I actually ran into this issue as well for multiple posts submissions. You have two options here:

1) Generate a new token AFTER post submission:

Session::put('_token', sha1(microtime()))

2) Redirect AFTER post to a confirmation page:

Redirect::route('form/success')->with("data", $myData)

I ended up doing the second.

EDIT: In a comment via Jason, it may be best to use the combination of both methods outlined above

Rob W
  • 9,134
  • 1
  • 30
  • 50
  • I'm also using a Redirect::route already to redirect to the created blog post after validation passes. In case of validation errors I use Redirect::back()->withInput()->withErrors(). BTW: You're the 1st one answering my first question :-) Thanks. I'd vote you up, but need 15 Rep first... – Markus Hofmann Jun 22 '13 at 20:14
  • There you go... I just waited, because some more answers could have bubbled up. – Markus Hofmann Jun 25 '13 at 15:13
  • @HalfCrazed I tried second option, but didn't work for me.The form gets submitted again. – Trying Tobemyself Jul 24 '13 at 15:43
  • So is the CSRF token being destroyed or reset automatically on the redirect, i.e. on landing on the non-form page? – Jason Sep 29 '13 at 16:57
  • 9
    To answer my question (I just tried this), no a redirect does not in validate the CRSF token. Even after a redirect to a "thank you" page, the user can push the back button and get back the complete form with populated data in, with the old CSRF token. The user can submit the form again without any errors being raised. So 2) alone is not enough to fixed this problem. It should be used in conjunction with 1) to reset the CSRF token in the session. – Jason Sep 29 '13 at 18:05