Friendly way to deal with invalid authenticity_tokens?

hey all. I'm using the hidden authenticity_token system in my rails
app. This is designed as a security measure but sometimes it kicks off
in response to fairly innocent user actions like clicking the back
button and then submitting a form, or submitting a form after the server
has just been restarted, or whatever.

That's not really important (i don't want to debate whether the above
should cause authenticity token fails). What is important is that it's
going to happen sometimes in response to non-hostile user actions, and
when it happens i don't want it to result in a crash screen for the
user: instead, something more friendly should happen.

I'm catching the exception with rescue_from, so from a technical point
of view i'm good, but now i can't work out what the best thing to
actually *do* is. What i'm doing as a baseline is just sending them to
the homepage with an error message in flash[:error]. This works from a
security point of view, and is much better than a 500 page, but i feel
like i could do something better. Any ideas? Is there a standard
practise for this?

grateful for any advice - max

Hi Max,

The strategy I usually follow is catch the error, log it (and check
logs periodically to make sure it's not really an xss attack), set a
msg for the user about the problem, and then redirect the user back to
where they came from, something along the lines of (in app/controllers/
application_controller.rb):

  ...
  rescue_from
ActionController::InvalidAuthenticityToken, :with=>:bad_auth_token

  ...
  def get_in_app_referer_url
    ref_url = request.referer
    # or some default if not coming from in app?
    ref_url = "/" if ref_url.blank? or ...
    return ref_url
  end

  def bad_auth_token
    # log it.
    logger.warn("....")
    # notify user.
    flash[:err] = "...."
    # send them back to try again.
    redirect_to(get_in_app_referer_url)
    return
  end
  ...

Jeff

Jeff Burlysystems wrote:

Hi Max,

The strategy I usually follow is catch the error, log it (and check
logs periodically to make sure it's not really an xss attack), set a
msg for the user about the problem, and then redirect the user back to
where they came from, something along the lines of (in app/controllers/
application_controller.rb):

Hi Jeff - thanks a lot. I'd thought about sending them back to the
previous (ie requesting-from) page but it seemed like the sort of thing
that could be rather tricksy and problematic and generally a pandora's
box of weird hard-to-predict problems. I guess if it's been your
strategy in the past then it's been ok for you?

One problem i thought of was to do with request methods: the page they
had been on might only be reachable from a post request for example, so
just sending them back to the same url wouldn't work. Similarly, you'd
want to recreate the params they had on that page as well. I've never
used request.referer though, does it just handle all of that stuff
automatically?

re: reachability of referer req: Yes, if the screen that they had
just submitted the post req from that resulted in the failure had
previously been reached via a post req, then they wouldn't be sent
back to that particular page. But, even if this were the case,
wouldn't (shouldn't?) the routing/rules you've defined for your app at
least redirect them to some other previous but related page via get?

Whenever possible, I try and structure my (non-ajax driven app)
screens such that each screen that contains a form that can result in
a post (or put or delete) req, or even handle user-input errors, that
screen is first rendered via a get request. This allows for that bad
auth token redirect strategy to work.

re: recreate the params: Yes, you could/would have to handle the
passing of the submitted params on to the redirected to screen
(controller meth) to handle for re-use/-render, but I've found such a
strategy becomes less viable the larger your app is (the more screens/
forms it contains that would need to be handled).

Bad auth token errors should be somewhat rare (unless it really is an
xss attack), so sending the user back to the screen where they came
from, letting them know there was a problem, and having them re-fill-
out the form and re-submit, seems like a reasonable enough way to
handle the problem imo (I haven't got any complaints from users so far
using this strategy).

Jeff

Jeff Burlysystems wrote:

re: reachability of referer req: Yes, if the screen that they had
just submitted the post req from that resulted in the failure had
previously been reached via a post req, then they wouldn't be sent
back to that particular page. But, even if this were the case,
wouldn't (shouldn't?) the routing/rules you've defined for your app at
least redirect them to some other previous but related page via get?

Yes, they *should*. :slight_smile:

Whenever possible, I try and structure my (non-ajax driven app)
screens such that each screen that contains a form that can result in
a post (or put or delete) req, or even handle user-input errors, that
screen is first rendered via a get request. This allows for that bad
auth token redirect strategy to work.

Yeah, again that's all good app design. I try to do this as well, you
just reminded me that i should add 'go to the current contents of the
address bar and see if anything weird happens' to my test scripts.

re: recreate the params: Yes, you could/would have to handle the
passing of the submitted params on to the redirected to screen
(controller meth) to handle for re-use/-render, but I've found such a
strategy becomes less viable the larger your app is (the more screens/
forms it contains that would need to be handled).

I think this is covered under the last point really: if all the pages
are 'reload-safe' then it's not so much of an issue.

Thanks a lot. i think the lesson generally is 'if you've designed your
app properly then it's fine'. Which is good to know.

cheers, max