CodeIgniter Forums

Full Version: CSRF only on POST request, reason?
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
I'm working on a project that has a larger REST API backend used by a HTML5, JS frontend. Making it fully RESTful I'm using all request types. GET, POST, PUT and DELETE.

All requests posting data to the API required a CSRF token. I have so far used my own solution for this but started looking at the included CSRF in CI. And I now have some general questions.

  1. Is there a reason why the CSRF is only validating the token for POST requests? I would like to have it on PUT requests as well.
  2. Is there any way to control the error message if the token is invalid or missing? Atm it loads a error view template. I would like to have it return JSON.
I'd be interested in responses to these questions as well. Incidentally, is there a way to subscribe to a thread without having to reply to it?

My personal take on 1. is that CI was reasonably confident that it could add CSRF protection to forms without too much risk of breaking everything since using form_open() automatically creates the hidden input field for the token. Even then, it looks like the forum still receives questions about POST requests failing which oftentimes turns out to be due to CSRF protection. On the other hand, there are no established CI mechanisms for PUT or DELETE requests since CI probably did not have these in mind in its earlier incarnations and would have an increased risk of breaking these requests for applications already using them. That said, this is all just conjecture on my part. For any RESTful requests, I just add the token in myself.
I guess you can at any time use CSRF protection for anything with: get_csrf_token_name() and get_csrf_hash() or am I wrong?
If you want, you can regenerate the CSRF in this way in your Controller.

Code:
$csrf = array(
           'name' => $this->security->get_csrf_token_name(),
           'hash' => $this->security->get_csrf_hash()
       );
(03-05-2015, 07:22 PM)silentium Wrote: [ -> ]Is there any way to control the error message if the token is invalid or missing? Atm it loads a error view template. I would like to have it return JSON.

You can do this by creating an application/core/MY_Security class which extends CI_Security. The simplest solution would be to override just the csrf_show_error() method, which would probably also be fairly easy to maintain in the long term (currently, in both CI 2 and 3, the method just calls show_error() with the message 'The action you have requested is not allowed.', though CI3 adds the 403 error code).

In theory, a quick read of the csrf_verify method indicates that it attempts to perform cookie-based CSRF verification for requests which are not POST requests.
(03-05-2015, 09:36 PM)Nichiren Wrote: [ -> ]Incidentally, is there a way to subscribe to a thread without having to reply to it?
Look in the upper right of the first post in the thread (also shows as first post of a page, if there are multiple pages). There is some text called "Thread Modes", click that and a dropdown will appear with a subscribe link. It's not very obvious because it's just text and not a button or something that stands out.
(03-06-2015, 09:36 AM)mwhitney Wrote: [ -> ]You can do this by creating an application/core/MY_Security class which extends CI_Security. The simplest solution would be to override just the csrf_show_error() method, which would probably also be fairly easy to maintain in the long term (currently, in both CI 2 and 3, the method just calls show_error() with the message 'The action you have requested is not allowed.', though CI3 adds the 403 error code).

In theory, a quick read of the csrf_verify method indicates that it attempts to perform cookie-based CSRF verification for requests which are not POST requests.

You are so right, I completely forgot that can just extend the CI_Security class... thank you.

The CSRF is stored in a cookie, however, CI only validate that cookie against POST requests. If the request is anything but POST, it just generate a new CSRF cookie.

CI_Class -> csrf_verify() line 208
PHP Code:
// If it's not a POST request we will set the CSRF cookie
if (strtoupper($_SERVER['REQUEST_METHOD']) !== 'POST')
{
 
  return $this->csrf_set_cookie();

(03-06-2015, 10:50 AM)silentium Wrote: [ -> ]The CSRF is stored in a cookie, however, CI only validate that cookie against POST requests. If the request is anything but POST, it just generate a new CSRF cookie.

CI_Class -> csrf_verify() line 208

PHP Code:
// If it's not a POST request we will set the CSRF cookie
if (strtoupper($_SERVER['REQUEST_METHOD']) !== 'POST')
{
 
  return $this->csrf_set_cookie();


Oops, you're right. I was reading that too quickly and apparently missed the return part.
In all honesty, CI is just not built for creating RESTful APIs ...

CSRF tokens are verified only on POST requests, because that's what almost all web forms submit, $_POST is easy to access and within a browser, you typically need to issue a GET request, so that you can submit the form in the first place (hence why != 'POST' actually assumes GET).
(03-06-2015, 01:14 PM)Narf Wrote: [ -> ]In all honesty, CI is just not built for creating RESTful APIs ...

CSRF tokens are verified only on POST requests, because that's what almost all web forms submit, $_POST is easy to access and within a browser, you typically need to issue a GET request, so that you can submit the form in the first place (hence why != 'POST' actually assumes GET).

Understandable. However, is it in the interest of CI to change/update this for the future. I'm not talking for CI3, but maybe CI4?