10

I have a web form and I'm using PHP. I'm aware that forms can be manipulated (I believe it's called replay attack or a man-in-the-middle attack). So I'd like to use some authenticity token as a hidden field.

The threat possibilities that I'm aware of are:

  • Attacker hijacks the legitimate user's form (this I believe is the man-in-the-middle attack)
  • the legitimate user is himself the attacker: he gets the form, reads the token but uses it to send dangerous data (this I believe is the replay attack)

Before I get to the questions, please correct me if anything I said so far is incorrect, because maybe my understanding is flawed.

Now to the questions:

  • What is the best practice to generate this token so that the form without it gets rejected (for example, salting?).
  • What do people do to make sure that the token isn't being replayed.

New small questions based on comments:

  • Is session hijacking the same as man-in-the-middle attack?
lorem monkey
  • 3,942
  • 3
  • 35
  • 49
Chris
  • 8,736
  • 18
  • 49
  • 56
  • For some reason I am thinking you are over-complicating this process. Why will data validation not suffice? Are you concerned with hijacked form data that someone would submit? And it is changed? Or login type forms? (which could be done over SSL to eliminate the man-in-the-middle-attack). – Jakub Oct 09 '09 at 17:34
  • Maybe I'm over-complicating it, I don't know. It seemed complicated and fraught with too many loopholes when I was reading about it. But question 1 is still valid since I don't know what's the best practice to generate that token :) Whether question 2 (the question about replaying a token) is valid or not, that I'm hoping to understand too. – Chris Oct 09 '09 at 17:49
  • You are definitely using the wrong verbage. It seems like you are talking about data validation mostly. – Trevor Harrison Oct 09 '09 at 17:54
  • 1
    Yes, the terms are wrong. What Chris is describing are session hijacking and XSRF. SSL protects against the first, site design against the second. – Steven Sudit Oct 09 '09 at 18:51
  • +1 Steven Sudit. So SSL can protect against session hijacking. Is SSL the only thing needed to protect against it, or the best, or it has to be used in combination with anything else? – Chris Oct 09 '09 at 20:36
  • 1
    SSL is a big help in that is hides your cookie from sniffing. But it won't stop your cookie from being stolen by XSS, so it's no magic bullet. – Steven Sudit Oct 10 '09 at 02:09
  • 2
    And, no, session hijacking is not man-in-the-middle. Session hijacking is impersonating you by passing your session cookie. Man-in-the-middle is a general type of attack based on telling each side that it's the other. It *can* be used for session hijacking, but it's more general than that. – Steven Sudit Oct 10 '09 at 02:14
  • Have a look here: http://stackoverflow.com/questions/2034281/php-form-tokens, this is a security form token that can be used to prevent any illegal actions on your forms. This will generate a unique token for each user and form and it will be checked(you have to check it) before update or add record to the DB – Alex Rashkov Sep 13 '11 at 13:46

4 Answers4

5

You mentioned CSRF in the title but didn't really cover it in your question.

You can read about it in detail online, but CSRF is basically an attack that lets a legitimate user submit to a site unknowingly. For instance, if SO wasn't protecting against such attacks, I could craft a form that causes your SO profile information to be changed when you click on this bad form of mine, expecting something else to happen ("Win a Million bucks!! Click here!!"). This form would use your browser cookies to auth you with SO and make it appear to SO that you were legitimately submitting updates to your profile.

To protect against this, you really want to do a couple of things:

  • ensure that GETs don't cause updates (for instance, don't post a new status update to a user's profile using query params on a GET)
  • ensure that all POSTs are accompanied by a hidden field that lets you validate that the form was generated by your service and not by someone else, and that it was for the intended user. So this hidden field must be generated by the server each time it sends down the html for the form, and should be unique for that user for that session.

An alternative to that second item is to check that the referrer is always your site or a site you expect the POST from. I don't encourage this for non-HTTPS sites because some browsers/networking hardware strip out referrers, and it's not always reliable that a referrer exists.

psychotik
  • 38,153
  • 34
  • 100
  • 135
3

The method used to generate the token is not highly important. The important thing is that the token gets to be used only once. Keep a list of tokens generated for the user in the user's session. If the user submits a form and the token submitted isn't in the session, you can reject the form.

Protecting against man-in-the-middle is a little difficult. A common technique I've seen is including all of the hidden form fields in the hash function to generate the token, and then regenerating the token based on known hidden fields. However, that would only protect against hidden field manipulation, which may not be the ultimate target of the man in the middle.

When the user successfully submits a form with the token, delete the token from the session, so any replay of that submission will fail. However, all it takes is the user requesting the form again to generate another token. That new token can then be used in subsequent automated attacks. In other words, form tokens are useful against CSRF, but not highly effective against automated replay and man-in-the-middle attacks.

Likewise, you're going to want to adapt your application to not require the use of the user's back button on forms. If there's an issue with their submission, you're going to need to return the form back to the user with their data filled in. If the user hits her back button to correct the error, her submission will then fail due to the now invalid token.

Also, to be frank, by the time you need to worry about request replays and man-in-the-middle attacks, your user's connection has already been compromised, and there's probably not much you can do to mitigate any damage. SSL alone is an adequate protection level against MITM and replay, and if you're that worried about it, you'll be running under SSL...

Charles
  • 50,943
  • 13
  • 104
  • 142
  • 2
    Or, in a few words: Just use SSL. – Steven Sudit Oct 09 '09 at 17:50
  • 3
    No, SSL doesn't do anything to prevent XSRF attacks, so "Just use SSL" doesn't cover it. – erickson Oct 09 '09 at 18:03
  • 2
    It does protect against session hijacking, which is the other concern Chris had. XSRF just isn't that big a risk unless you violate the rules psychotik outlined by allowing gets to change things. – Steven Sudit Oct 09 '09 at 18:53
  • If the attacker controls the user's browser, then there is no way to protect the user. All protection implemented in the browser can be circumvented by the attacker. – Siqi Lin Jul 04 '10 at 05:23
1

To generate that token, here's a strategy I use that seems to work well.

  • Set a cookie to a random value (generated on the server using the usual tricks) and set it to expire according to your needs.
  • When serving up a page with a form, embed a hidden field whose value equals the value of this cookie.
  • When handling the post, validate that this field exists, and that the value matches the user's cookie
psychotik
  • 38,153
  • 34
  • 100
  • 135
  • [You cannot use cookies to protect against CSRF](https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#Using_a_Secret_Cookie) – Domi May 01 '15 at 12:27
0

csrf-magic is a great class for CSRF tokens, it puts them into your page automatically

http://csrf.htmlpurifier.org/

"csrf-magic uses PHP's output buffering capabilities to dynamically rewrite forms and scripts in your document. It will also intercept POST requests and check their token (various algorithms are used; some generate nonces, some generate user-specific tokens). This means, for a traditional website with forms, you can drop csrf-magic into your application and forget about it!"

ejfrancis
  • 2,925
  • 4
  • 26
  • 42