Nicolás, Please don't go into details too much for the example case I came up with. I already mentioned in my first post, that if the poll is of any real concern, it would of course have been put behind a login. And while we're at it, SSL login, with a 2-tier authenticator device and iris-scan, just to be sure. And we need to verify their real ID before allowing signup, because email-verification is not enough as people can create them on-the-fly.
I realize that protection-by-ip-address is not very safe, but for the poll example I gave, it might be just enough. I beg to differ that there are a lot of websites out there using exactly that. Working around it is easy, you can use a bunch of proxys, tunnel request through tor, employ a botnet and probably more. But by far the easiest (if you own a website) is to just have your visitors perform the action on your behalf. So I'm not saying anything about whether or not ip-protected polls are good or bad practice, I'm just arguing it's a valid use case, which was protected by default with the old CSRF protection. Thanks, Mathijs On Feb 12, 9:45 am, Nicolás Sanguinetti <[email protected]> wrote: > On Sat, Feb 12, 2011 at 6:40 AM, Mathijs <[email protected]> wrote: > > On Feb 12, 8:05 am, Michael Koziarski <[email protected]> wrote: > >> CSRF attacks are about using *session* data to perform an action > >> without the user's knowledge. The attack you're describing here, > >> which doesn't rely on session data, could also be performed just using > >> curl from the command line of the attackers laptop, there's no need to > >> involve the user's computer at all. > > > Except for him not being able to vote twice using curl with the same > > IP address. > > The attack allows him to command other people (his visitors) to > > perform actions on my site. > > In my opionion, the 'session riding' part of CSRF is not just about > > the physical session/cookie object, just as much about starting new > > sessions. (so session as in "the order in which requests are made", we > > only allow a signup if you first asked for the signup form). > > But no matter what we think CSRF protection is about, the old behavior > > was about validating every potentially harmful request, the new one a > > specific type of attack, which was already covered by the old one. > > So we can conclude that the security got loosened somewhat (for > > reasons you mention below). > > >> If there's no involvement of the session (or some other > >> client-browser-specific) vector, then it's not a CSRF attack. > > > As mentioned, I think starting a new sessions from a "clean" IP > > address counts as client-browser specific. > > So you're saying people with dynamic IPs which rotate every 12 hours > (the majority of Uruguay, for example) should just log in into your > site each time the IP rotates, or am I reading it wrong? > > > > > > > > > > >> However you're correct that we need a little more documentation than > >> we had previously because the attack vectors are a touch trickier. I > >> intend to post an FAQ blog post and update the guides in a few days to > >> ensure that it's crystal clear what's required. > > > I'm glad we agree documentation is the key. > > >> The thing to remember is that we *can't* raise an exception in the > >> default case any more because *every api request would be rejected*. > >> For users who don't have any API, then the original behaviour was > >> probably fine. However a large portion of rails apps do and we can't > >> completely break them! > > > That's why my API controllers inherit from ApiController instead of > > ApplicationController, and I don't put the CSRF protection in there. > > Instead, api calls need an API key param to verify their origin. Also > > there's "skip_before_filter :verify_authenticity_token" to bypass CSRF > > protection on a controller or action basis. > > This is probably what most apps with an API use, because - as you > > point out - there are already a large number of rails apps out there > > with an API, working with the old system. So I don't see how they > > would be broken. > > > I agree it's nice we can now configure the behavior ourselves, instead > > of having to fully bypass it, all I'm saying is that for the default > > case making sure a request is dropped sounds best to me. The API case > > should indeed be able to easily switch to other behavior (for certain > > controllers probably). > > >> I see your point and agree that we need a little more documentation > >> around this. However it is nowhere near as simple as your suggestions > >> imply. Developers will have to understand the implications of their > >> choices. > > > Indeed, of their own choices. > > But since the default (rails generator) "application" already contains > > 'protect_from_forgery', which just doesn't do anything unless they > > start using the session as a security measure, you can't really hold > > every dev responsible for expecting that they are protected against > > forged requests from other sites. > > >> I suspect we'll end up with an api like: > > >> protect_from_forgery :on_failure=>:raise > >> protect_from_forgery :on_failure=>:reset > >> protect_from_forgery :on_failure=>:some_method > >> protect_from_forgery :on_failure=> proc { ... } > > > That sounds like a nice api > > >> I realise that the previous situation where you could just ignore the > >> issue was greatly preferable, but that was based on some assumptions > >> which don't hold. The old rules don't apply anymore. > > > I don't really see why. The old system was easy to bypass for specific > > controllers and actions, while the default was safe for all abuse- > > cases. The new system is aimed towards applications with an api that > > don't want to use skip_before_filter and that do use a session for > > their security-measures. > > What assumption does not hold anymore? Which rule changed? > > >> > Mathijs > > >> > On Feb 11, 9:51 pm, Jon Leighton <[email protected]> wrote: > >> >> Hi there, > > >> >> As you've identified, the difference between 2.3.10 and 2.3.11, and > >> >> between 3.0.3 and 3.0.4, in how they handle invalid csrf tokens is that > >> >> the former will raise ActionController::InvalidAuthenticityToken, but > >> >> the latter will reset the session. > > >> >> What we are trying to protect against is the following situation: > > >> >> * Alice is logged in to Facebook > >> >> * Alice visits badsite.com > >> >> * Mallory, who owns badsite.com has added some code into the page which > >> >> makes a request to facebook.com and posts on Alice's wall. > >> >> * Alice visits badsite.com and without her intending it to be, a comment > >> >> is posted on her wall > > >> >> With the current CSRF protection, the following will happen: > > >> >> * Alice is logged in to Facebook > >> >> * Alice visits badsite.com > >> >> * Mallory, who owns badsite.com has added some code into the page which > >> >> makes a request to facebook.com and posts on Alice's wall. > >> >> * Alice visits badsite.com and without her intending it to be, a request > >> >> is made to post on her wall > >> >> * Facebook detects that there is no CSRF token associated with the > >> >> request, and so logs her out by resetting the session > >> >> * Then, based on the authorisation rules within the application, > >> >> Facebook denies to post on the wall, because the user is not logged in > > >> >> With the old CSRF protection, the following will happen: > > >> >> * Alice is logged in to Facebook > >> >> * Alice visits badsite.com > >> >> * Mallory, who owns badsite.com has added some code into the page which > >> >> makes a request to facebook.com and posts on Alice's wall. > >> >> * Alice visits badsite.com and without her intending it to be, a request > >> >> is made to post on her wall > >> >> * Facebook detects that there is no CSRF token associated with the > >> >> request and so refuses to serve the request in any way (returns 500) > >> >> * So nothing gets posted on the wall > > >> >> The point is, they are different but both have the effect of preventing > >> >> the wall post. > > >> >> If for some reason you specifically want an exception to be raised in > >> >> this situation, you can customise handle_unverified_request, but it > >> >> doesn't compromise the aim of the CSRF protection to no raise an > >> >> exception, so long as the request is not allowed to go through as > >> >> authenticated by the existing session. > > >> >> Jon > > >> >> On Fri, 2011-02-11 at 11:28 -0800, Mathijs wrote: > >> >> > Hi all, > > >> >> > I think CSFR protection broke in rails 2.3.11. > >> >> > As in: it's turned off now. > > >> >> > I tried this in rails 2.3.10 and in 2.3.11 and 2.3.11 seems broken. > > >> >> > >rails csrftest > >> >> > >cd csrftest > >> >> > >script/generate scaffold post title:string > >> >> > >rake db:migrate > > >> >> > now I visit /posts/new in my browser, use firebug to delete or change > >> >> > the authenticity token, and submit the form. > > >> >> > rails 2.3.11: all fine, new post saved > >> >> > rails 2.3.10: ActionController::InvalidAuthenticityToken > > >> >> > I checked ApplicationController to see if it still contained > >> >> > "protect_from_forgery", which is the case. > >> >> > I read the announcement for the csrf changes in 2.3.11 and they talk > >> >> > about overriding handle_unverified_request for special cases where > >> >> > there are other ways for authenticating a user. In this simple case I > >> >> > demonstrated though, there is no concept of a user or logging in (or a > >> >> > session), so the default action of resetting the session is not very > >> >> > useful. > >> >> > In my opinion, CSRF protection is about verifying a request. It > >> >> > doesn't have anything to do with users/sessions/authentication. > >> >> > By default, a faulty request (unprotected/wrong token) should not > >> >> > reach the normal controller action code at all, so the main action to > >> >> > take when a non-verified request comes in, is to have the > >> >> > before_filter chain halt. nothing more, nothing less. > >> >> > Extra stuff (like destroying a session) is up to the user (or nice to > >> >> > leave in as a default). > >> >> > So I think the behavior in 2.3.11 is just wrong, because in the > >> >> > example I gave, the forms just get submitted and stuff gets persisted > >> >> > to the database. > >> >> > It's not clear from the announcement at all that you should now make > >> >> > sure the filter chain halts, or that you must protect your actions by > >> >> > something that's stored in the session (because that's all that gets > >> >> > done when a faulty request hits). > > >> >> > Maybe I'm just doing something wrong here, please let me know. > >> >> > Mathijs > > >> >> --http://jonathanleighton.com/ > > >> >> signature.asc > >> >> < 1KViewDownload > > >> > -- > >> > You received this message because you are subscribed to the Google > >> > Groups "Ruby on Rails: Core" group. > >> > To post to this group, send email to [email protected]. > >> > To unsubscribe from this group, send email to > >> > [email protected]. > >> > For more options, visit this group > >> > athttp://groups.google.com/group/rubyonrails-core?hl=en. > > >> -- > >> Cheers > > >> Koz > > > -- > > You received this message because you are subscribed to the Google Groups > > "Ruby on Rails:... > > read more » -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en.
