1

I am trying to add a token to my forms in order to prevent CSRF attacks

But the token validation isn't working

Here is the input field which holds the token

<input type="hidden" name="auth_token" value="<?php echo $_SESSION['auth_token']; ?>"> 

And here is the token validation code

 if ($_SERVER["REQUEST_METHOD"] == "POST") { // Validate token to avoid CSRF $auth_token = $_POST["auth_token"]; if (!$auth_token || $auth_token != $_SESSION['auth_token']) { // show an error message echo '<h1 class="error">Error: invalid form submission</h1><p>Your request was denied as this request could not be verified.</p>'; // return 405 http status code header($_SERVER['SERVER_PROTOCOL'] . ' 405 Method Not Allowed'); exit(); } // process form here } 

It doesn't work and it returns the error message in the if block

4
  • 2
    This really needs some basic debugging. e.g. work out why the test is failing. echo out the values you are comparing. Figure out if the token has changed or if it isn't set for starters. Commented Mar 7, 2022 at 8:10
  • 2
    A 405 error is wrong here. POST methods are allowed. It's the data in the POST request that is wrong. 403 would make more sense. Commented Mar 7, 2022 at 8:11
  • @Quentin I compared the values and they happen to be different, but i can't seem to figure out why Commented Mar 7, 2022 at 8:31
  • From the information you've provided, nor can we. It probably has something to do with the code you use to generate the tokens (and specifically when you call it) but you haven't shared that with us. Commented Mar 7, 2022 at 9:15

1 Answer 1

1

I presume that the submitted auth_token value is something random such as hwm7wherlwkju or whatever. Testing !$auth_token could give special results, depending if it's missing or if it contains "1", "true" or "". Secondly, use !== instead of != to avoid automatic type casting in the comparaison.

So I would replace your "if" condition with this:

session_start(); // 1) Check if the recieved token is valid. if (!isset($_POST['auth_token']) || !isset($_SESSION['auth_token']) || $_POST['auth_token'] !== $_SESSION['auth_token']) { // Show an error message. echo "<h1 class=\"error\">Error: invalid form submission</h1>\n" . "<p>Your request was denied as this request could not be verified.</p>\n"; // Return a 403 error. http_response_code(403); die(); } // 2) Generate a new token for the next request if you are displaying a page with a <form>. $_SESSION['auth_token'] = bin2hex(random_bytes(20)); 

About the token value generated, I think you should also check that you are not generating a new value in the session on each request before doing the comparaison for validation. The comparaison should be done first and then a new token value should be generated and stored in the session.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks alot, the last part of your answer was the solution. However won't regenerating the token on every new request pose a problem for users using my site on multiple tabs ?
Well, what you could do is generate a token for each <form> with a specific id, meaning that you could store a dictionnary with multiple tokens, each one affected to the generated page. Each time you validate the token you delete it from the list. And ideally, each token should have a max age, let's say 30 minutes or so.
Oh.. I guess that works fine..

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.