Home Logout

Tutorial: How to set up login accounts

WARNING

The current implementation of an authenticating and authorization procedure (Password Login) in CGIscriptor.pl is experimental and meant as an illustration for the use of the framework. The code has not been reviewed.
Before you use this procedure on your site, be sure you understand the limitations of the implemented procedures. You should evaluate first whether the procedures address your security needs and second whether the code implements the procedures correctly.

Introduction

In situations where pages and services must be limited to authorized persons, it is possible to activate a login procedure when a certain page or url is requested. The authentication is done by requesting a user name and a password. The server stores information about the passwords and privileges of individual users.

The method used to authorize requests is a server side session ticket. The client (user) browser will send an identifier token that is compared with the expected identifier. Only if the token is accepted, will the requested page be processed and send to the client. Identifier tokens can be send as cookies or as CGI variables. There is no difference between these two methods. If possible, use cookies as they are more convenient. Note that the ticket identifiers rely on the use of browser SessionStorage. If the browsers of clients do not support browser SessionStorage, your choices will be limited.

How to protect services with a password login

The variable %TicketRequiredPatterns contains a set of URL patterns that should be protected by a password login. Each pattern points to a directory where login sessions are stored (Private/.Sessions), account information (Private/.Passwords), the login page that should be shown for that URL (Private/Login.html), and finaly the default expire time for a session (+36000, i.e., 36 thousand seconds = 10 hours).

# File patterns of files which are handled by session tickets.
%TicketRequiredPatterns = (
'^/Private(/|$)' => "Private/.Sessions\tPrivate/.Passwords\t/Private/Login.html\t+36000"
);

Session types

Security comes with costs attached. The more stringent the authentication should be, the more complex the authentication process will have to be. To allow a meaningful tradeof between security and costs, three levels of authentication are implemented.

  1. IPADDRESS: Remote client IP address
    Use the (apparent) IP address of the client as an identification. Simple and not secure
  2. SESSION: Single session token
    Create a single token that the client can use during the session. But also use the IP address. Relatively straightforeward and reasonably secure.
  3. CHALLENGE: One time session tokens
    The client has to generate a new token for every request. Each token can be used only once. The new token is constructed from a random string send from the server and the stored password. This can be used to prevent session hijacking by a third party who can simulate the same IP address, or if the IP address is not fixed, e.g., when using Tor.
It is adviced to use the SESSION (single session token) type unless there are specific reasons to increase security, eg, for the admin acount or Tor sessions.

Password account tickets

This is an annotated example of a PASSWORD account ticket. At the right hand side is the literal text as present in the Account file. All regex patterns are Perl regex patterns.

The type of the ticket Type: PASSWORD
Official username, lower cast Username: testchallenge
Hashed and encrypted password Password: 6df7d66e8832ee52a9aba5e474ce8641a9577eff140d54b297b61443bf8d9eb1
Allowed IP addresses, a regex pattern IPaddress: 127.0.0.1
Allowed paths in the web site, a regex pattern AllowedPaths: ^/Private/index\.html$
idem AllowedPaths: ^/Private/[^/]+\.html$
idem AllowedPaths: ^/Private/?$
Privileges, in this case allowed to hop proxies Capabilities: VariableREMOTE_ADDR
The server salt used to hash the password Salt: e93cf858a1d5626bf095ea5c25df990dfa969ff5a5dc908b22c9a5229b525f65
Allowed session type Session: CHALLENGE
A signature of important aspects of this ticket Signature: eca5b95e3ff4a9628be4c6f1fca29ec2f5981cbbba0b29ce5b601055926a8720
Maximum lifetime of a session, 45 minutes MaxLifetime: +45m
The above account contains a contradiction. Although it has Capabilities: VariableREMOTE_ADDR, it is also limited to the local machine, IPaddress: 127.0.0.1 (IPaddress is matched from the start). The default account in this example has been locked down for distribution. Shipping a default account that could be accessed from the outside would be a security hazard. You are adviced to change the password before you change any of the default accounts.

An example Create User Account page is added. When logged in as any user, you can go to this page and enter your own password (the one you used to log in), the user name, and password of the new user. Below that, the allowed pages and IP addresses can be entered as a ; separated list of regular expression patterns. After sumitting the form, the text of the account file will be printed on the page. These texts can be saved in the .Passwords directory. However, if the admin account is activated, that user can create active new accounts directly. With each new user, a home directory is automatically created as a copy of the Private/.SkeletonDir directory.

Account signatures and activation

Reading the passwords or any change in the account files by other users of the servers could lead to a compromize of the system. Therefore, it is possible to encrypt passwords and sign accounts (and session tickets). If the web server supports an environment variable with the name CGIMasterKey ($ENV{CGIMasterKey}), the value of that variable will be used as a pass phrase. $ENV{CGIMasterKey} will be used to encrypt the password and create a signature of the account and session tickets. Any account or session ticket with an invalid signature will be discarded. Both the encryption keys and the signatures will be constructed from the server side salt and the user name. This means that if you change the server side salt or CGIMasterKey, you will have to reset all passwords and recreate all signatures.

Activating an account means that the password is set and a correct signature is created. Setting passwords and generating signatures can be done with CGIscriptor.pl on the command line. The following command will set a new password and signature for the testchallenge account:
perl CGIscriptor.pl --managelogin salt=Private/.Passwords/SALT masterkey='Sherlock investigates oleander curry in Bath' password='testing' Private/.Passwords/testchallenge
Note that the creation time of the account (if present) will be part of the signature. This will make that every new account file will have a unique signature. Even if all the other contents are the same. The password is not part of the signature, nor are any comments.

Creating web pages

IPADDRESS and SESSIONtype sessions do not require any changes in web pages after login. CHALLENGE type sessions require JavaScript code on every single protected page (actually, only to get to the next page after that). Use of the back button is not possible in CHALLENGE type sessions. To add support for the login sessions to simple web pages, add the following code to the HEAD section of each HTML file:

<script type="text/javascript">
<SCRIPT TYPE="text/ssperl" SRC="./JavaScript/PlainPage.js"></SCRIPT>
</script>

Pages that require a user to enter username or password require special window.onload code as well as special onSubmit code for the FORM fields, eg, LoginSubmit(), ChangePasswordSubmit (), and CreateUserSubmit (). For the Login page, change PlainPage.js into LoginPage.js in the above code snippet. For Change Password and Create User use, respectively, ChangePasswordPage.js and CreateUserPage.js. The following FORM ID and CGI parameter names should be used (FORM element ID):

FORM ID and CGI parameter names that are optional as they are set by the server and also exchanged by cookies. All contain server generated hexadecimal hashes. Use the FORM ID versions when you use form fields instead of cookies:

In some cases it might be needed to defer setting the SESSION cookie at the login submit to the landing page. To achieve this, remove setSessionParameters();true from the onSubmit function in the Login.html page:

onSubmit='LoginSubmit();setSessionParameters();true'
should become:
onSubmit='LoginSubmit()'
In those cases you will have to add JavaScript code to the first page after the login.