CSRF token expired when page is left open |
Hello!
When a user enters a page that has a form, if he spends a lot of time with that page open and tries reload the page, it will throw a security exception. In the app/Config/Security.php file there is an expiration set at the default 7200(2 hours). Is there any solution other than increasing these seconds so that when this time passes, and the user re-enters the page, reload the page from the beginning so as not to throws a security exception???
Disable regenerate tokens https://codeigniter4.github.io/userguide...generation
(01-09-2024, 11:40 PM)ozornick Wrote: Disable regenerate tokens https://codeigniter4.github.io/userguide...generationIt's already disabled. The problem is the expiration after 2 hours. Some users forget the page open and then go back to try submit the form. If i enable the redirect config in security class, does it prevent exception from being throw??
I don't remember, but it will refresh the page and may reset the entered data. Tried.
01-17-2024, 09:44 AM
(This post was last modified: 01-17-2024, 09:55 AM by Valkhan. Edit Reason: Found a solution )
I'm facing the same issue with CI 4.4.0, I've turned on an error monitoring and this is bloating my reports with unhandled errors.
Well, I took some time to understand how the framework validates the CSRF token and I was shocked that despite having an "expires" config, if does not check the expiration of the token while validatin the CSRF token: The verify method: /** * CSRF Verify * * @return $this * * @throws SecurityException */ public function verify(RequestInterface $request) { // Protects POST, PUT, DELETE, PATCH $method = strtoupper($request->getMethod()); $methodsToProtect = ['POST', 'PUT', 'DELETE', 'PATCH']; if (! in_array($method, $methodsToProtect, true)) { return $this; } $postedToken = $this->getPostedToken($request); try { $token = ($postedToken !== null && $this->tokenRandomize) ? $this->derandomize($postedToken) : $postedToken; } catch (InvalidArgumentException $e) { $token = null; } // Do the tokens match? if (! isset($token, $this->hash) || ! hash_equals($this->hash, $token)) { throw SecurityException::forDisallowedAction(); } $this->removeTokenInRequest($request); if ($this->regenerate) { $this->generateHash(); } log_message('info', 'CSRF token verified.'); return $this; } As we can see, the postedToken received by the request is checked only if it's equals to the current hash. I tried using regenerate = true and tokenRandomize = true, but to no avail, i've set the expires to 10s and the hash didn't get regenerated after multiple page refresh; I'm not certain if CSRF is fully functional at this point after testing this behavior, now i'm worried. What I was trying to achieve is to instead of throwing an error (exception) I would handle the error by returning a 403 failed response and that would solve the issue of expired tokens bloatin my error monitor. It would be nice to have an entry point to handle errors caught on filters, but I do not have knowledge if that feature exists. After some testing, the only fix I found was to enable csrfProtection = session because when the session expires the hash wil be regenrated, and then my solution worked. Quote:If you use Session, be sure to use Session based CSRF protection. Cookie based CSRF protection will not prevent Same-site attacks. See GHSA-5hm8-vh6r-2cjq for details. (01-17-2024, 09:44 AM)Valkhan Wrote: What I was trying to achieve is to instead of throwing an error (exception) I would handle the error by returning a 403 failed response and that would solve the issue of expired tokens bloatin my error monitor. You can create your own CSRF filter based on the framework CSRF filter: https://github.com/codeigniter4/CodeIgni...hp#L55-L63 and see https://www.codeigniter.com/user_guide/i...g-a-filter |
Welcome Guest, Not a member yet? Register Sign In |