When sending any data that is persistent (like a cookie) to the client, you should ALWAYS include a hash (like MD5 or SHA1) of the original value so you can easily see if the cookie value has been modified.
Anyone who modifies the cookie can also recompute the hash value so that it matches. To prevent that, you need to include secret information in the hash itself -- see Digest::HMAC
. If you go that route, you can eliminate the need to store session information on the web server at all.
$cookie = join(",", $user_name, $time, $remote_ip);
$cookie .= "," . unpack("H20", hmac_sha1($cookie, $secret));
(I cut the hash down to 80 bits, because that should be enough to prevent a brute-force key search.) Then your only problem is keeping $secret synchronized, if you have a pool of load-balanced servers. Verifying the cookie against both the current secret and the previous secret should give you some leeway so the servers don't all have to be updated at the same instant. It'll also avoid invalidating everybody's current logins when you change the secret.
Update: Yes, that's basically what I meant, drewbie. HMAC is a construction that avoids some possible weaknesses when using a hash as a MAC.
Possible Objection: An attacker who breaks into the web server and learns $secret can log in as anyone.
Response: He can probably forge himself a new Apache::Session, too. Or trojan the login cgi so it saves the passwords in a log file.