Date: 08/23/00
- Previous message: jk: "[phplib-dev] cvs commit"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Hi, folks.
This is my first posting here, and I don't know if this is the right
place to do it, so please redirect me to the right place if it is
needed.
I've written a new container class: ct_cookie.inc; it saves session data
in cookies. It does data compression using gzcompress() and provides md5
validation so an evil user could not change the session data.
Another (optional) feature is data encryption. When it's enabled, the
user cannot see what is inside the cookie. That's why I've also included
arc_four.inc, which is a class that implements RC4 compatible
encryption, but any other algorithm can be used if its implementation is
provided.
I wrote this container for small apps, that do not need to store large
amounts of data. It is useful also for those that cannot modify their
server parameters to use phplib (pages that uses ct_cookie.inc doesn't
need any special sql/db/file configuration - scripts can work out of
box).
It works almost perfect with my existing apps (you have to change them
to NOT TO USE GET METHOD).
I know that cookies are unreliable, but there are lots of scripts that
use them without providing any alternate method. PHPLIB doesn't, but I
wrote this container for those who doesn't care (I'm one of them).
I've included an working example that should work in any phplib-7.2c
installation out-of-the-box. No changes needed!
Please reply with your comments.
-Alejandro Vazquez C.
Source code follows...
----- ct_cookie.inc -----
<?php
/*
Copyright (c) 2000 Alejandro Vázquez C. <alexv <email protected>>
This file is distributed under the GNU Lesser General Public
License version 2, as distributed by Free Software Foundation.
Please contact FSF for a copy of the licence terms:
Free Software Foundation Voice: +1-617-542-5942
59 Temple Place - Suite 330 Fax: +1-617-542-2652
Boston, MA 02111-1307, USA gnu <email protected>
PHPLIB Data Storage Container using Cookies.
*/
class CT_Cookie
{
var $magic = false;
# CHANGE THIS! It is dangerours not to do it.
var $gzlevel = 0; # This is the level of compression
desired.
# 0 = no compression, 1 = fast -> 9
= smaller
# false = default setting of
gzcompress().
var $lifetime = 0;
# Lifetime in minutes for cookies.
# 0 = session cookies.
var $cookie_max_length = 3968; # Maximum size for every single
cookie.
# The spec says it can be up to
4kb.
var $max_cookies = 2;
# Maximum allowed number of cookies.
# The spec says it can be up to
20.
# Maximum amount of data =
4kb*20 = 80kb!
# However, Apache rejects any
request
# whose headers are larger than
8190.
# That's why I choose those
values,
# 3968 * 2 = 7936 (maximum
session
# data size).
# You'd need to patch Apache to
overcome
# this situation.
var $cookie_domain = '';
# Domain for cookies.
var $enable_buffering = true;
# Set to false if you don't want to
# use ob_start()/ob_end_flush(),
however
# you would need to call
page_close()
# before any output is made.
var $encrypt_class = false;
# Name of the class implementing a
# (de)ciphering algorithm.
# false = no encryption
(plaintext).
var $encrypt_key = false;
# Encryption key.
var $last_md5 = false;
# Internal variable (to avoid setting the
# same cookie twice).
function ac_start()
{
if(false===$this->magic)
$this->ac_halt('CT_Cookie: you need to change the magic
value!<br>'.
' If it is known, a hacker can take over your
server!');
if($this->enable_buffering)
{
ob_start();
register_shutdown_function(create_function('',
'ob_end_flush();'));
}
}
function encode_val($val)
{
if(false===$this->gzlevel)
$gzval = gzcompress($val);
else if(0!==$this->gzlevel)
$gzval = gzcompress($val, $this->gzlevel);
else
$gzval = $val;
$md5_val = md5($this->magic . ":{$val}");
if(false !== $this->encrypt_class)
{
if(false === $this->encrypt_key)
$this->ac_halt('CT_Cookie: you have to setup the key before
using encryption!');
$eclass = $this->encrypt_class;
$cipher = new $eclass;
$cipher->setupKey(md5($this->magic . ':' . $this->encrypt_key));
$gzval = $cipher->encrypt($gzval);
}
$encoded_val = $md5_val . base64_encode($gzval);
if(strlen($encoded_val) > ($this->cookie_max_length *
$this->max_cookies))
return false;
$splitted = array();
while(strlen($encoded_val) > $this->cookie_max_length)
{
$splitted[] = substr($encoded_val, 0, $this->cookie_max_length);
$encoded_val = substr($encoded_val, $this->cookie_max_length);
}
$splitted[] = $encoded_val;
return $splitted;
}
function decode_val($val)
{
if(is_array($val))
$encoded_val = implode('', $val);
else
$encoded_val = $val;
if(!ereg('^([0-9a-z]{32})([0-9A-Za-z/+=]+)$', $encoded_val,
$splitted))
return false;
$md5_val = $splitted[1];
$gzval = <email protected>($splitted[2]);
if(false !== $this->encrypt_class)
{
if(false === $this->encrypt_key)
$this->ac_halt('CT_Cookie: you have to setup the key before
using encryption!');
$eclass = $this->encrypt_class;
$cipher = new $eclass;
$cipher->setupKey(md5($this->magic . ':' . $this->encrypt_key));
$gzval = $cipher->decrypt($gzval);
}
if(0 !== $this->gzlevel)
$val = <email protected>($gzval);
else
$val = $gzval;
if(md5($this->magic . ":{$val}") !== $md5_val)
return false;
return $val;
}
function ac_store($id, $name, $str)
{
global $HTTP_COOKIE_VARS;
$encoded_val = $this->encode_val($str);
if(false === $encoded_val)
return false;
$md5 = substr($encoded_val[0], 0, 32);
if((0 === $this->lifetime) && ($this->last_md5 === $md5))
return true;
reset($encoded_val);
$then = time()+$this->lifetime*60;
$i = 0;
while(list(, $chunk) = each($encoded_val))
{
$cookie_ptr = "{$name}_" . chr($i + 97);
if(0 < $this->lifetime)
SetCookie($cookie_ptr, $chunk, $then, '/',
$this->cookie_domain);
else
SetCookie($cookie_ptr, $chunk, 0, '/', $this->cookie_domain);
$HTTP_COOKIE_VARS[$cookie_ptr] = $chunk;
$i++;
}
for(; $i < $this->max_cookies; $i++)
{
$cookie_ptr = "{$name}_" . chr($i + 97);
if(isset($HTTP_COOKIE_VARS[$cookie_ptr]))
{
SetCookie($cookie_ptr, '', 0, '/', $this->cookie_domain);
unset($HTTP_COOKIE_VARS[$cookie_ptr]);
}
}
return true;
}
function ac_get_value($id, $name)
{
global $HTTP_COOKIE_VARS;
if($HTTP_COOKIE_VARS[$name] != $id)
return '';
$encoded_val = '';
for($i = 0; $i < $this->max_cookies; $i++)
{
$cookie_ptr = "{$name}_" . chr($i+97);
if(!isset($HTTP_COOKIE_VARS[$cookie_ptr]))
break;
$encoded_val .= $HTTP_COOKIE_VARS[$cookie_ptr];
}
if(strlen($encoded_val) < 1)
return '';
$val = $this->decode_val($encoded_val);
if(false === $val)
return '';
$this->last_md5 = substr($encoded_val, 0, 32);
return $val;
}
function ac_delete($id, $name)
{
global $HTTP_COOKIE_VARS;
if($HTTP_COOKIE_VARS[$name] != $id)
return;
for($i = 0; $i < $this->max_cookies; $i++)
{
$cookie_ptr = "{$name}_" . chr($i+97);
if(isset($HTTP_COOKIE_VARS[$cookie_ptr]))
{
SetCookie($cookie_ptr, '', 0, '/', $this->cookie_domain);
unset($HTTP_COOKIE_VARS[$cookie_ptr]);
}
}
}
function ac_newid($str, $name)
{
return $str;
}
function ac_halt($s)
{
echo "<b>{$s}</b>";
exit;
}
function ac_get_lock()
{
# Nothing needed by now
}
function ac_release_lock()
{
# Nothing needed by now
}
function ac_gc($gc_time, $name)
{
# Nothing needed by now
}
}
?>
----- arc_four.inc -----
<?php
/*
Copyright (c) 2000 Alejandro Vázquez C. <alexv <email protected>>
This file is distributed under the GNU Lesser General Public
License version 2, as distributed by Free Software Foundation.
Please contact FSF for a copy of the licence:
Free Software Foundation Voice: +1-617-542-5942
59 Temple Place - Suite 330 Fax: +1-617-542-2652
Boston, MA 02111-1307, USA gnu <email protected>
This class provides an ciphering engine compatible with RC4.
If you feel that needs to be improved, go on.
------
To implement an alternative encoding you need to declare a class
with the following methods:
function setupKey($key);
It should do everything that is needed to start encoding/decoding
with the supplied key.
function encrypt($val);
It must encode the plaintext stored in $val, and return its
ciphertext.
function decrypt($val);
It must decode the ciphertext stored in $val, and return its
plaintext.
encrypt()/decrypt() can change the state of the underlying object, so
multiple
calls to these function with the same data COULD return diferent
values.
However, every call pair to setupKey()/encrypt() and
setupKey()/decrypt()
with the same data MUST return the same result.
*/
class ARC_FOUR
{
var $state;
var $x, $y;
function swapbyte($i, $j)
{
$temp = $this->state[$i];
$this->state[$i] = $this->state[$j];
$this->state[$j] = $temp;
}
function setupKey($key)
{
$this->state = array();
for($c = 0; $c < 256; $c++)
$this->state[$c] = $c;
$this->x = 0; $this->y = 0;
$i = 0; $j = 0;
$key_len = strlen($key);
for($c = 0; $c < 256; $c++)
{
$j = (ord($key[$i]) + $this->state[$c] + $j) % 256;
$this->swapbyte($c, $j);
$i = ($i + 1) % $key_len;
}
}
function do_rc4($val)
{
$val_len = strlen($val);
$x = $this->x; $y = $this->y;
$ret = '';
for($c = 0; $c < $val_len; $c++)
{
$x = ($x + 1) % 256;
$y = ($this->state[$x] + $y) % 256;
$this->swapbyte($x, $y);
$xorI = ($this->state[$x] + $this->state[$y]) % 256;
$ret .= chr(ord($val[$c]) ^ $this->state[$xorI]);
}
$this->x = $x; $this->y = $y;
return $ret;
}
function encrypt($val)
{
return $this->do_rc4($val);
}
function decrypt($val)
{
return $this->do_rc4($val);
}
}
?>
----- local.inc -----
<?php
require("ct_cookie.inc");
require("arc_four.inc");
class CookieCT extends CT_Cookie
{
var $lifetime = 40;
var $gzlevel = 9;
var $magic = "SomethingWeird";
var $encrypt_class = "ARC_FOUR";
var $encrypt_key = "A que no adivinas que dice aquí";
}
class CookieSession extends Session
{
var $classname = "CookieSession";
var $cookiename = "Cookie";
var $magic = "MyMagic";
var $mode = "cookie";
var $lifetime = 40;
var $that_class = "CookieCT";
var $allowcache = "no";
}
?>
----- index.php -----
<?php
page_open(array('sess' => 'CookieSession'));
if('kill' === $QUERY_STRING)
{
$sess->delete();
print "This session has been killed.<br>\n";
print "<a href=$PHP_SELF>Reload</a>\n";
exit;
}
$sess->register('value');
settype($value, 'integer'); # Shouldn't phplib do this for me?
switch($QUERY_STRING)
{
case 'reset':
$value = 0;
break;
case 'substract':
$value--;
break;
case 'add':
$value++;
break;
}
print "Value: $value<br>\n";
print "<a href=$PHP_SELF?add>Add</a><br>\n";
print "<a href=$PHP_SELF?substract>Substract</a><br>\n";
print "<a href=$PHP_SELF?reset>Reset</a><br>\n";
print "<a href=$PHP_SELF?kill>Kill session</a><br>\n";
page_close();
?>
- application/octet-stream attachment: ct_cookies.tgz
---------------------------------------------------------------------
To unsubscribe, e-mail: phplib-dev-unsubscribe <email protected>
For additional commands, e-mail: phplib-dev-help <email protected>
- Previous message: jk: "[phplib-dev] cvs commit"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]

