/program/lib/tokenlib.php - functions to manipulate unique tokens via the database
This file provides the functions to manipulate tokens stored in the database. These tokens are used to create unique instances of dialogs (forms) making it impossible to POST data to a form without first retrieving the individual (blank) form to start with.
Tokens are stored in a table called 'tokens' which is defined as follows:
+--------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------------+--------------+------+-----+---------+----------------+ | token_id | int(11) | | PRI | NULL | auto_increment | | token_key | varchar(60) | | MUL | | | | token_ref | varchar(60) | | | | | | token_start | int(11) | | | 0 | | | token_end | int(11) | | | 0 | | | token_expire | int(11) | | | 0 | | | remote_addr | varchar(150) | | | | | | data | longtext | YES | | NULL | | +--------------+--------------+------+-----+---------+----------------+
Note: this table was added in v0.90.5 (June 2013), initially for the mailpage module.
The following functions are defined.
$token_id = token_create($ref, &$token_key, $delay_start, $delay_end, $ip_addr); $token_id = token_lookup($ref, $token_key, &$timer_start, &$timer_end, &$ip_addr, &$data); $retval = token_store($token_id, $data); $retval = token_fetch($token_id, &$data); $retval = token_destroy($token_id); $retval = token_garbage_collect();
create a new record in the tokens table, return the unique token_id
this creates generates a new unique token_key and stores it in a new record in the tokens table. Additional information is recorded in the new record too:
The parameter $reference is used to further limit the chance that POST'ing a rogue token_key could influence another, valid $token_key. This $reference could be a number identifying a particular dialog definition, e.g. by using the filename and a line number in a define().
Finally, the IP-address of the visitor is recorded. This can be used in the future to limit brute force attacks on a form. Currently it is not used other than to add to the mail that is sent via the mailpage module. Note that by default we use the IP-address from $_SERVER but the caller is free to substitute something else, perhaps a canonical IPv6-address.
We call the garbage collector from here. This keeps the table clean. Furthermore, we have got the time: the user has to wait at least $delay_start seconds before she can submit anything, so I think there is no rush. YMMV.
remove a token record from the tokens table (it should still exist)
remove the specified record from the table. it is an error if the record does not exist.
retrieve the (unserialised) data from the database
remove all expired tokens
this removes all records that are expired. Since this routine is also called from token_create() we have a big chance to keep the tokens table clean. However: logging every delete() may be a little too much so it is commented out.
This way, the worst that can happen is that someone keeps GET'ting a form that uses tokens every second for 8 hours in a row and subsequently nobody ever visits that form again. In that case we eventually have 8 x 3600 x 1 = 28800 garbage records. Oh well.
OTOH: with all those crawlers and spiders on the WWW there is bound to be a 'bot' visiting that form the next day, effectively cleaning up for us. (Robots are a feature, not a bug...)
lookup $reference + $token_key in the table and retrieve token information
This checks the existence of a token record in the tokens table. This $token_key can only generated via token_create(). Furthermore, we require that the $reference matches the one in the record. This prevents us accepting spurious token keys via manipulated requests. If the key does not exist, the call fails and FALSE is returned, otherwise the token_id is returned + data in the other parameters (timers, remote_addr, etc).
Typical use:
if (($token_id = token_lookup($ref, $key, $t0, $t1, $ip_addr, $data)) === FALSE) { logger('error: no such token'); } elseif (time() < $t0) { logger('error: whoa, not so fast there!'); } elseif ($t1 < time()) { logger('error: too late'); } else { logger('welcome visitor from '.$ip_addr); }
This allows for accepting POST'ed information only within the time window defined by $t0 and $t1 and denying access otherwise with a precise cause (no token, too early, too late).
write the (serialised) data to the database
serialise and store $data in the database
Documentation generated on Tue, 28 Jun 2016 19:12:17 +0200 by phpDocumentor 1.4.0