How to prevent Cross-site request forgery (CSRF) e

2019-03-20 02:41发布

问题:

I am trying to prevent CSRF in php in the following way:

  1. A $_SESSION['token'] is generated at the start of each page. I already know that using $_COOKIES is completely wrong since they are send automatically for each request.

  2. In each <form>, the following input: <input type="hidden" name="t" value="<?php echo '$_SESSION['token']; ?>"> is appended.

  3. The $_SESSION['token']; is validated with the $_POST['t']

Now I have several small questions:

  • Is this a good way to prevent CSRF? If not please explain.
  • When another page is opened as well that sets the same $_SESSION variable, the previous (still open) page becomes invalid, how to prevent this?
  • For forms this method is clear, but how to handle normal links? Is it necessary to append the token to each link as well?

Thank you very much in advance.

回答1:

Is this a good way to prevent CSRF?

Yes. What this does is to force the client to do a GET on the form before it can do a POST to your form handler. This prevents CSRF in modern browsers since browsers will prevent client-side Javascript to do an XHR GET request to a foreign domain, so a 3rd party cannot imitate your form on their site and successfully get a valid token for the submission.

When another page is opened as well that sets the same $_SESSION variable, the previous (still open) page becomes invalid, how to prevent this?

Allow several tokens to be valid at a time, keeping an array of valid tokens in the session. Alternatively, store no tokens at all and use a token signing scheme instead. I've dabbled in and explained that here. Alternative 2: just use a single token for the whole session, without invalidating tokens. (tip o' the hat to @SilverlightFox in the comments)

For forms this method is clear, but how to handle normal links? Is it necessary to append the token to each link as well?

No. You only need to protect POST requests since presumably only POST requests can alter sensitive data (wink wink nudge nudge, you're sticking to REST conventions, right?!) and XHR GET requests are already blocked browser-side.