Safely propagating user access roles between session requests
This note documents how roles are propagated from one request to the next without accessing the server's authorization file every time.
- AES-192 symmetric encryption is employed to hide roles.
- Cookies are used to carry the encrypted data.
- Timestamps and idle-time thresholds are used to renew and expire authorized sessions.
- IP addesses provide an additional safety value against hacker replay attacks.
When a user successfully authenticates through a login request, the server responds by returning a cookie that contains an encrypted list of roles assigned to the user. These roles are matched against subsequent requests to determine whether or not the user has permission to access the requested resource using the requested method.
Once a session cookie has been created, no further interaction with the roles file is necessary. This is referred to as stateful roles.
Special precautions need to be taken to prevent intentional misuse of this mechanism through alteration or hacker replay attacks.
In order to prevent a bad actor from altering the cookie and obtaining illegitimate access, the roles are subjected to the AES-192 symmetric-key encryption algorithm. That algorithm uses a cipher key to encrypt the roles before they are sent to the browser and to decrpyt the roles when they return to the server through an incoming request.
The cipher key used in this encryption/decryption process is an arbitrary value chosen by the webmaster. (Note that this cipher key has nothing to do with the user's password authentication procedure.)
In order to prevent bad actors from capturing the encrypted cookie and replaying it at a later time, the cookie has a limited period of validity. A timestamp is added to the data structure used to store the user's assigned roles, and that timestamp, together with a duration, defines the period of time during which the cookie is valid.
The webmaster configures the duration using the
max-idle entry, which specifies the number of seconds that the cookie is valid, as counted from the time captured when the user logged in. The login timestamp is carried inside the cookie's data structure.
It should be noted that the
max-idle time is not strictly an expiration time limit. Rather, it is a half-life counter, with automatic renewal. When new requests arrive within the first half of the
max-idle's life, they are processed as expected. When new requests arrive within the second-half of the
max-idle's life, the request is honored, and the cookie is renewed. In this way, a user that continues to make requests — that are no more than
max-idle seconds apart — will continue to stay logged in.
In order to further protect against replay attacks, the user's IP address is encrypted and added to the cookie's data structure during login. When subsequent requests receive the cookie, the decrypted IP address is compared against the incoming request's IP address and mismatches are denied.
An RBAC request may fail for several reasons. Appropriate status codes and information headers are returned as follows:
|Triggering event||Information header||Resulting action|
|Cookie has been tampered with|| ||Request fails with status code 403.|
|Cookie's remote address differs|| ||The "anonymous" role is used.|
|Timestamp is too old|| ||The "anonymous" role is used.|
|Timestamp is in 2nd half-life|| ||A fresh |
rw-rbac cookie's encryption algorithm requires an arbitrary cipher key that is unforgeable, but forgettable, that is, the webmaster can set it once and not think about it again. The
cipher-secret entry is used for this. It may be changed safely, during periods of quiet activity, with the only side effect being that currently active users will need to login again. It should never be exposed to the public and never added to a git repository.
max-idle entry should be configured with some reasonable number of seconds. Typical values are: 1200 (20 minutes), 5400 (90 minutes), 86400 (24 hours). Smaller values provide a shorter window of time for any potential replay attack to be successful, but at the cost of annoying the user, who may want to legitimately use the website without such fuss.
The roles file, which is created by the
addrole CLI utility, and used by the RW-Auth handler, is specified in this same section, using the
roles entry. This entry should contain the fully qualified, absolute path to the roles file. Be sure to delimit this path by enclosing it in GRAVE-ACCENTs.
|file-system-chars||::=||(ALPHA | DIGIT | †)*|
|roles-file-entry||::=||'roles' SP GRAVE-ACCENT file-system-chars GRAVE-ACCENT CR|
|cipher-secret-entry||::=||'cipher-secret' SP visible-ascii* CR|
|max-idle-entry||::=||'max-idle' SP (0..9)* CR|
|rbac-section||::=||'rbac' SP LEFT-CURLY-BRACKET CR|
† Legal file system characters vary by platform
Example: RBAC stateful roles configuration
This is a partial RBAC configuration, showing only the entries used for cookie based stateful roles. A more complete example is provided in the note that covers the RBAC handler itself.
roles `/etc/rwserve/roles` // the file created by the 'addrole' CLI utility
cipher-secret C#9fB$2gD@5zR*7e // secret used to encrypt the 'rw-roles' cookie
max-idle 1800 // number of seconds of inactivity before credentials expire
Key points to remember:
- A user's assigned roles are carried in the
rw-rbaccookie in encrypted form.
- The RBAC handler user stateful roles to determine whether a uses has appropriate privileges to requested resources.