PHP form token usage and handling
Asked Answered
S

3

17

I'm a beginner working on a login script in PHP. This is the form token statement that I have so far:

$_SESSION["form_token"] = md5(rand(time (), true)) ;

The statement is issued just after the user indicates that he/she wants to login.

My limited understanding is that the tokens purpose is to identify a unique user at a unique point in time and to disguise the form token information.

Then everything becomes fuzzy. Here are my 3 open questions:

  1. When is the best time to "check" the form token for security purposes?

  2. How do I check it?

  3. When, if ever, do I "destroy" the form token? (IOW, would the form token stay "active" until the user logs out?

Submariner answered 9/1, 2010 at 17:50 Comment(2)
FYI MD5 is somewhat limited and if you need to generate a random string I suggest you use this instead: $id = sha1(mt_rand()); If you use rand() you only get have 32,000 possible combinations.Nerta
related: #5111507Syringa
E
15

There is no need to do what you are attempting. When you start a session in PHP with session_start() a unique SESSIONID is already generated for you. You should not be putting this on the form. It is handled via cookies by default. There is also no need to check the SESSIONID either, that again is handled for you.

You are responsible for authenticating the user and storing their authenticated identity (e.g. $_SESSION['user_id'] = $userId in the SESSION. If a user logs out you destroy their session with session_destroy.

You should ensure session_start() is one of the first things for all pages in your site.

Here is a basic example:

<?php
session_start(); // starts new or resumes existing session
session_regenerate_id(true); // regenerates SESSIONID to prevent hijacking

function login($username, $password)
{
    $user = new User();
    if ($user->login($username, $password)) {
        $_SESSION['user_id'] = $user->getId();
        return true;
    }
    return false;
}

function logout()
{
    session_destroy();
}

function isLoggedIn()
{
    return isset($_SESSION['user_id']);
}

function generateFormHash($salt)
{
    $hash = md5(mt_rand(1,1000000) . $salt);
    $_SESSION['csrf_hash'] = $hash
    return $hash;
}

function isValidFormHash($hash)
{
    return $_SESSION['csrf_hash'] === $hash;
}

Edit: I misunderstood the original question. I added the relevant methods above for generating and validating form hashes;

Please see the following resources:

Eller answered 9/1, 2010 at 17:55 Comment(1)
There is something I don't understand. I also use php sessions for tokens, but each time I modify one session, all of them get modified (the "date modified" of all tmp files changes). Is there any connection between sessions that identify different users?Casias
A
19

this is to prevent CSRF attacks

http://en.wikipedia.org/wiki/Cross-site_request_forgery

a malicious site could theoretically display a form that posts to your application. the form might contain instructions that cause a data breach or some unwanted action. the user might be deceived into submitting the form which the app would accept because the user is already logged in. a form token ensures the form was created by your site and not some other site.

checking the HTTP_REFERER is often good enough, but not as complete a solution (https for instance won't send the referrer string).

if you really want to secure all forms with a token, you can create some convenience functions like emitToken() and checkToken() that will make it work site-wide.

some examples:

http://phpsec.org/projects/guide/2.html

http://www.rodsdot.com/php/CSRF_Form_Protection.php

Aspidistra answered 9/1, 2010 at 17:54 Comment(1)
HTTP_REFERER is NOT trustable, never rely on it because it can easily be edited!Anastomosis
E
15

There is no need to do what you are attempting. When you start a session in PHP with session_start() a unique SESSIONID is already generated for you. You should not be putting this on the form. It is handled via cookies by default. There is also no need to check the SESSIONID either, that again is handled for you.

You are responsible for authenticating the user and storing their authenticated identity (e.g. $_SESSION['user_id'] = $userId in the SESSION. If a user logs out you destroy their session with session_destroy.

You should ensure session_start() is one of the first things for all pages in your site.

Here is a basic example:

<?php
session_start(); // starts new or resumes existing session
session_regenerate_id(true); // regenerates SESSIONID to prevent hijacking

function login($username, $password)
{
    $user = new User();
    if ($user->login($username, $password)) {
        $_SESSION['user_id'] = $user->getId();
        return true;
    }
    return false;
}

function logout()
{
    session_destroy();
}

function isLoggedIn()
{
    return isset($_SESSION['user_id']);
}

function generateFormHash($salt)
{
    $hash = md5(mt_rand(1,1000000) . $salt);
    $_SESSION['csrf_hash'] = $hash
    return $hash;
}

function isValidFormHash($hash)
{
    return $_SESSION['csrf_hash'] === $hash;
}

Edit: I misunderstood the original question. I added the relevant methods above for generating and validating form hashes;

Please see the following resources:

Eller answered 9/1, 2010 at 17:55 Comment(1)
There is something I don't understand. I also use php sessions for tokens, but each time I modify one session, all of them get modified (the "date modified" of all tmp files changes). Is there any connection between sessions that identify different users?Casias
M
0

You could check out the zend framework implementation.

Apart from the specific implementation, the docs describe the reasoning and usage of this kind of element on a form.

Its Zend_Form_Element_Hash https://docs.zendframework.com/zend-form/element/csrf/

Messy answered 9/1, 2010 at 18:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.