TIP: Use Markdown or, <pre> for multi line code blocks / <code> for inline code.
These forums are read-only and for archival purposes only!
Please join our new forums at discourse.kohanaframework.org
CSRF Helper
  • This isn't really a feature request per se. It is a feature completely implemented and ready to be included into the Kohana core. Code is available here:
    http://pastie.org/387747

    (written by those present in the IRC channel the past few hours).

    I also volunteer to document its usage and explain the need if it is decided this is worth including in Kohana.
  • To give some context:

    This helper is for Cross Site request forgery protection. (http://en.wikipedia.org/wiki/Cross-site_request_forgery)

    It is to be used to insert a unique token per user-session on each form that is delivered to a user. This makes sure that any form submissions are verified to have originated from the actual site and not some other location.
  • The main reason why I would suggest its inclusion is to help make new developers more aware of security issues when developing for the web. Simply including this in the documentation would mean that copy/paste developers will do it right (and have a shot at knowing why it is there) and that will do wonders for the web ecosystem.
  • Did you even look at the existing XSS filtering in the core ?

    If so, why is your implementation better ?
  • XSS and CSRF are two different things. Maybe this could be added to the form helper? Something like <?=form::csrf()?>, would create a hidden input with the csrf token. I'm not sure it really needs it's own class.
  • dougal2:
    This isn't XSS, this is CSRF--they're different. See Blake's post for a discussion of CSRF. This isn't a better thing, it doesn't exist in core and the point to include it would be to make developers more aware of this attack vector.

    Best.
  • If a form helper is added there would also need to be an additional validation rule added to the Validation helper. I would also be a good idea to add a "Security" section to the docs, discussing how to handle most common security concerns in Kohana.

  • i dont really think a helper is required for this. I do this "by hand" in my forms:


    <?=form::open()?>
    <?=form::hidden('token', $_SESSION['token'] = text::random())?>


    Then in my form processor (maybe a validation method) something like:


    if ($_POST['token'] != arr::remove('token', $_SESSION))
    die('NO')


    This also has the added benefit of reducing to eliminating spam without a captcha.
  • I would also be a good idea to add a "Security" section to the docs, discussing how to handle most common security concerns in Kohana.

    I think this would be the best thing. Use the php methods available to you instead of pointlessly slowing your code down with a wrapper class.

  • I would use it simply for its valid() method, making it easy to add a Validation rule instead of adding an if statement to your code

  • Advantages of having a CSRF helper in core:
    - Less verbose at usage point.
    - DRY. CSRF protection should exist on every action that requires login privileges and writes data to the server. Cuts down on possible mistakes.
    - More easily included into validation.
    - More easily introduce people to proper web practices. Copy and Paste coders will copy it straight out of the documentation and do it right.

    Disadvantages of including a CSRF helper in core:
    - More code included in the core. However, this isn't like a JavaScript library where kilobytes matter (Zend is GIGANTIC). I'd say this is minor.

    Disadvantages of using the CSRF helper:
    - Slower than a one-off approach. But if you know enough to care about execution time of the CSRF helper, you know enough to code your own one-liners that will be faster.

    Also, an addressable issue that has existed with all of the one-liners thrown around: if a user has multiple tabs open to your site with CSRF protected forms, the session token is overwriting itself, leading to form-submission "race" conditions.

    One can always make the argument that it is simple to write X yourself with regards to helpers (form elements, etc). I feel that one of the main reason helpers exist are to make it easy to do the right thing. I would say that this falls squarely into that category and that the positive aspects of including a helper in the core greatly outweigh the negatives.
  • Isaiah, since we spoke I came up with a situation where it made sense to split a CSRF helper from the Form helper: if I were writing AJAX code and wanted to simply output the token into a global variable so that it is always accessible (that is a lot easier than document.getElementById('csrf').innerText).

    This is not to say that it doesn't make sense to also alias the CSRF helper into the form helpers too.
  • I realised my confusion in the few minutes between posting and falling alseep. d'oh! Perhaps I should refrain from internetting late at night.

    This is certainly an informative thread, Thanks.
  • Helper (and site) won't work if user opens some browser windows (tabs) simultaneously and will try to post the form.

  • This is only a problem if the user opens two windows with the CSRF session assignment in it (two windows with the same form). And even then, you run it thru validation, so all they have to do is submit the form again (their fields are pre-filled in), then it will work.

  • bio, the helper as it is coded does work if the user opens multiple tabs to the same form simultaneously. This was a topic of discussion as we were coding it. Have a test run with it and you'll see: it only sets the session key once and subsequently uses the pre-existing value.

    However, the one-liner as demonstrated in the forums fails with multiple tabs open to any form page with CSRF protection. It overwrites the session key each time the page is requested. This can be slightly mitigated by using differently named session variables for keys for different forms (not hard to do with a one-liner, even unintentionally), but you're still polluting the session.

    And zombor, I don't find that unnecessarily failing the CSRF test a great way to instill confidence in your users. (And still vote for inclusion. *grin*)
  • @nathanhammond I agree that CSRF is important, but how one protects against it is open to interpretation. We use CSRF tokens within our code, but our generation method is completely different to yours as we're not relying on any session variables.

    Therefore I believe this shouldn't be included in the core, you're welcome to create a project for it over on the projects.kohanaphp.com site.
  • I added a CSRF section to the newly created Security page. I designed the section so other examples can be added that use different approaches. Please review.

  • Posted By: samsoir

    @nathanhammond I agree that CSRF is important, but how one protects against it is open to interpretation. We use CSRF tokens within our code, but our generation method is completely different to yours as we're not relying on any session variables.

    Therefore I believe this shouldn't be included in the core, you're welcome to create a project for it over on the projects.kohanaphp.com site.



    I would vote that it absolutely should be in the core and if someone wants to they can override it with a different functionality using a custom/extended helper. Kohana "aims to be secure, lightweight, and easy to use." - the first thing on the list is secure and even though CSRF protection is not difficult to implement, the fact that there is a standard will improve the perception and reality of it being secure.
  • I know this is quite an old thread but just a warning, you need to be careful as using code like this:

    if ($_POST['token'] != arr::remove('token', $_SESSION)) die('NO')

    If you don't visit the form, the $_SESSION['token'] isn't set. All you need to then do is send the form without the token and you'll break the protection (since $_POST['token'] is NULL and so is arr:remove('token', $_SESSION)). The one on the documentation security page correctly checks that there is a token value, but anyone using the 2 methods suggested on this form, I'd highly recommend you add an extra check to make sure the token has a value, otherwise your protection is useless.

    On a side note, why not add the CSRF helper functions you mention in the wiki to the security helper?

  • Another revival for this old topic.. when walking home from work today I was thinking about the csrf problem:

    1. One-time keys. One-time keys work when you don't use multiple tabs/windows with forms requiring the key - one submit invalidates the other's key. The same goes for example when you have a list of comments which can be deleted with ajax - clicking delete on one comment invalidates all the other keys. Works in applications like Flash games where refresh keys in every so seconds.

    2. Time restricted keys. Limiting keys to work for a certain period of time solves the multiple tabs/windows/keys per page problem. But then you have a key you can mis-use for that period time too, and face a problem when the key expires before the user submits the form or finishes reading and deleting comments on a page.

    3. Uid restricted keys. Restricting the key to the user uid (or computer id or what ever unique id per user) gives you more security against using the same key with other users but doesn't expire.

    4. Solutions?

    * Creating a hash of the url, uid and a random key per link added to keys array in session? But the keys array might grow quite big.. * Create a random key and store it to session and do the above, having the same csrf key for one page instead of one link and the keys wouldn't work after the users logs off?

    Maybe the best solution would just limit the keys by time (create a key with uid and creation stamp and maybe hash of url and when checking validity decrypt the key and check it's age and referer) and accept that the same key can be used for multiple times from the same page? Actually yes, maybe that's the only solution and we don't need to put anything in session either, unless a session restricted key too :D

    Comments?

  • Hello!

    Actually, I think the best solution is the one implemented in vBulletin forums, and that I also used a lot of times in codeigniter projects. Basically, build the token using user specific information AND a time string, through a two-pass encryption. Please note that this is just to give you a generic idea of how this could work, as I generally prefer not to give away how our security libraries work in detail.

    So, for example:

    sha1($userinfo['userid'].$userinfo['username'].$csrf_secret);

    This will build the constant user token, with $csrf_secret being a secret string setup in your application - but you can go crazy and customize this as you want. This token is NEVER viewable directly to the outside world.

    The final request token outputted to the user and in the form will then be:

    sha1($timenow.$this->user_token).'-'.$timenow;

    Now, when you get an input, in the backend you split the token, and do something like:

    $splittoken = explode('-', $request_token);
    $token = $splittoken[0];
    $time = $splittoken[1];
    if($token !== sha1($time . $this->user_token))
  • Thanks everyone, really helpful thread.
  • In Kohana 3 cookies are created with salt, don't they?

    $value = cookie::salt($name, $value).'~'.$value;
    return setcookie($name, $value, $expire, $path, $domain, $secure, $httponly);

    code from Cookie::set

    So, when using sessions, Kohana automatically does the same as your helper?

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion