ACS Documentation : ACS Kernel Documentation : Security Documentation : Design
The atoms used in the implementation:
Cookies provide client side state. They are used to identify the user. Expiration of cookies is used to demark the end of a session.
This secure hash algorithm enables us to digitally sign cookies which guarantee that they have not been tampered with. It is also used to hash passwords.
SSL provides the client with a guarantee that the server is actually the server it is advertised as being. It also provides a secure transport.
One consequence of this security design is that secure tokens are not automatically issued to users who authenticate themselves over insecure connections. This means that users will need to reauthenticate themselves over SSL when performing some action that requires secure authentication.
Although this makes the site less user friendly, this design significantly increases the security of the system because this insures that the authentication tokens presented to a secure section of the web site were not sniffed. The system is not entirely secure, since the actual authentication password can be sniffed from the system, after which the sniffer can apply for a secure authentication token. However, the basic architecture here lays the foundation for a secure system and can be easily adapted to a more secure authentication system by forcing all logins to occur over HTTPS.
Details
The authentication system issues up to four signed cookies (see below), with each cookie serving a different purpose. These cookies are:
name value max-age secure? ad_session_id session_id,user_id SessionTimeout no ad_user_login user_id Infinity no ad_user_login_secure user_id,random Infinity yes ad_secure_token session_id,user_id,random SessionLifetime yes
Authentication Process
The Tcl function sec_handler) is called by the request
processor to authenticate the user. It first checks the
ad_session_id cookie. If there is no valid session in
progress, a new session is created with
ad_assign_session_id. If the user has permanent login
cookies (ad_user_login and
ad_user_login_secure), then they are looked at to
determine what user the session should be authorized as. Which cookie
is examined is determined by whether or not the request is on a secure
connection. If neither cookie is present, then a session is created
without any authentication. If the ad_session_id cookie
is valid, the user_id and session_id are pulled from it and put into
ad_conn.
Authenticating Secure Connetions
Secure connections are authenticated slightly differently. The
function ad_secure_conn_p is used to determine whether or
not the URL being accessed is requires a secure login. The function
simply checks if the location begins with "https". (This is safe
because the location is set during the server initialization.)
If secure authentication is required, the ad_secure_token
cookie is checked to make sure its data matches the data stored in
ad_session_id. This is true for all pages except those
that are part of the login process. On these pages, the user can not
yet have recevied the appropriate ad_secure_token cookie,
so no check against it is performed. The set of pages that skip that
processing are determined by determined by ad_login_page.
It is important to note that the integrity of secure authentication
rests on the two Tcl function ad_secure_conn_p and
ad_login_page. If ad_secure_conn_p is false,
secure authentication is not required. If ad_login_page
is false, secure authentication is not required.
Login Process
The Tcl function ad_user_login does two things. First it
performs the appropriate manipulation of the permanent login cookies,
and then it updates the current session to reflect the new user_id.
The manipulation of the permanent login cookies is based on 3 factors:
previous login state permanent login requested secure connection action on insecure action on secure other y y set set same y y set set other y n set delete same y n set nothing same n y nothing delete other n y delete delete other n n delete delete same n n delete delete
ad_user_login calls ad_assign_session_id
which actually calls sec_generate_session_id_cookie to
generate the new cookie with reference to the appropriate user_id. If
the connection is secure the ad_secure_token is generated
by a call to sec_generate_secure_token_cookie. This
function is only called from ad_session_id. Only
sec_handler and ad_assign_session_id call
sec_generate_session_id_cookie.
ad_user_logout logs the user out by deleting all 4
cookies that are used by the authentication system.
Passwords
ad_user_login assumes a password check has already been
performed (this will change in the future). The actual check is done
by ad_check_password. The database stores a salt and a
hash of the password concatenated with the salt. Updating the password
(ad_change_password) simply requires getting a new salt
(ns_time) concatentaing and rehashing. Both the salt and the hashed
password field are updated.
Performance Enhancements
Creation of a session requires incrementing the session_id sequence,
and inserting into the sec_sessions table. To speed this
process, we preinsert into the table, cache the session_id's and do an
insert instead. The cache is refreshed by a
sec_preallocate_session which runs every
PreallocatedSessionUpdateInterval seconds. It refills the pool of
preallocated sessions to PreallocatedSessionPoolSize. The preallocated
sessions are stored in an nsv list.
sec_sweep_session which removes sessions whose first hit
was more than SessionLifetime seconds (1 week by default) ago. Session
properties are removed through that same process with cascading
delete.
Secure Session Properties
Session properties can be set as secure. In this case,
ad_set_client_property will fail if the connection is not
secure. ad_get_client_property will behave as if the
property had not been set if the property was not set securely.
A cookie under this scheme will have a VALUE field that consists of a <data,expire_time,token_id,hash> tuple, where hash = SHA1(data,expire_time,token_id,secret_token). The secret_token is a forty character randomly generated string that is never sent to any user agent. The scheme consists of one table:
create table secret_tokens (
token_id integer
constraint secret_tokens_token_id_pk primary key,
token char(40),
timestamp sysdate
);
Every time the cookie is requested by the server, the cookie information is validated before returned to the calling procedure. Cookie information is validated by reconstructing the hash from the cookie data and comparing it to the stored hash in the cookie.
In addition to the expiration of the digital signature, RFC 2109 specifies an optoinal max age that is returned to the client. For most cookies, this max age matches the expiration date of the cookie's signature. The standard specifies that when the max age is not included, the cookie should be "discarded when the user agent exits." Because we can not trust the client to do this, we must specify a timeout for the signature. The SessionLifetime parameter is used for this purpose, as it represents the maximum possible lifetime of a single session.
RFC 2109 specifies this optional "secure" parameter which mandates that the user-agent use "secure means" to contact the server when transmitting the cookie. If a secure cookie is returned to the client over https, then the cookie will never be transmitted over insecure means.
Performance
Performance is a key goal of this implementation of signed cookies. To
maximize performance, we will use the following architecture. At the
lowest level, we will use the secret_tokens table as the
canonical set of secret tokens. This table is necessary for multiple
servers to maintain the same set of secret tokens. At server startup,
a random subset of these secret tokens will be loaded into an ns_cache
called secret_tokens. When a new signed cookie is
requested, a random token_id is returned out of the entire set of
cached token_ids. In addition, a thread-persistent cache called
tcl_secret_tokens is maintained on a per-thread basis.
Thus, the L2 ns_cache functions as a server-wide LRU cache that has a minimum of 100 tokens in it. The cache has a dual purpose:
Security
Storing information on a client always presents an additional security risk.
Since we are only validating the information and not trying to protect it as a secret, we don't use salt. Cryptographic salt is useful if you are trying to protect information from being read (e.g., hashing passwords).
ad_user_logout Logs the user out.
ad_check_password user_id password returns 0 or 1.
ad_change_password user_id new password
ad_get_signed_cookie name Gets the signed cookie name. It raises an error if the cookie has been tampered with, or if its expiration time has passed.
ad_secure_conn_p is true).
ad_get_client_property module name data
Gets a session property with name to for the module
module. The optional secure flag specifies the property should
only be retrieved if the client is authorized for secure access
(ad_secure_conn_p is true).
SessionLifetime the maximum possible lifetime of a session in seconds (default 604800 = 7 days)
PreallocatedSessionPoolSize the number of sessions to preallocate (default 600)
PreallocatedSessionPoolUpdateInterval how often to refill preallocated pool (default 120)
NumberOfCachedSecretTokens the number of secret tokens to cache. (default 100)
ns_rand function for its randomness. The implementation
of the PRNG could be substantially improved.
ad_user_login