Once a user logs in, the server sends back to the client a cookie
with an authentication token.
A suggested token would look like this:
Where t is the expiration time of the token (say, in several hours),
data (say, the user name or session id), and the digest is a keyed digest.
Feel free to change the field name of ``data'' to be more descriptive
(e.g., username or sessionid).
The keyed digest should be a cryptographic
hash of the expiration time and the data concatenated.
If you have more than one field of data (e.g., both a username and a
sessionid), make sure the digest uses both the field names and data values
of all fields you're authenticating; concatenate them with a pattern
(say ``%%'', ``+'', or ``&'')
that can't occur in any of the field data values.
The keyed digest should use HMAC-MD5 or HMAC-SHA1, using a different server
key (key2).
If this key2 is compromised, anyone can authenticate to the server, but
it's easy to change key2 - when you do, it'll simply force currently
``logged in'' users to re-authenticate.
See Fu [2001] for more details.
From then on, the server should check the expiration time and the digest
of this authentication token, and only server the data if it matches.
If there's no token, it could reply with the user login page
(with a hidden form field to show where the successful login should go).
If you include a sessionid in the authentication token, you can limit
access further.
Your server could ``track'' what pages a user has seen in a given session,
and only permit access to other appropriate pages
(e.g., only those directly linked from those page(s)).
For example,
if a user is granted access to page foo.html, and page foo.html has
pointers to resources bar1.jpg and bar2.png, then accesses to bar4.cgi
can be rejected.
You could even kill the session, though only do this if the authentication
information is valid (otherwise, this would make it possible for
attackers to cause denial-of-service attacks on other users).
This would somewhat limit the access an attacker has, even if they
successfully hijack a session, though clearly an attacker with time
and an authentication token
could ``walk'' the links just as a normal user would.
One decision is whether or not to require the authentication token and/or
data to be sent over a secure connection (e.g., SSL).
If you send an authentication token
in the clear (non-secure), someone who intercepts the
token could do whatever the user could do until the expiration time.
Also, when you send data over an unencrypted link, there's the risk of
unnoticed change by an attacker; if you're worried that someone might change the
data on the way, then you need to authenticate the data being transmitted.
Encryption by itself doesn't guarantee authentication, but it does make
corruption more likely to be detected, and typical libraries can support
both encryption and authentication in a TLS/SSL connection.
In general, if you're encrypting a message, you should also authenticate it.
If your needs vary,
one alternative is to create two authentication tokens - one is used
only in a ``secure'' connection for important operations, while the other
used for less-critical operations.
Make sure the token used for ``secure'' connections is marked so that only
secure connections (typically encrypted SSL/TLS connections) are used.
If users aren't really different, the authentication token could omit
the ``data'' entirely.
Again, make sure that the pages with this authentication token aren't cached.
There are other reasonable schemes also; the goal of this text is
to provide at least one secure solution.
Many variations are possible.