Home Logout

Change Password
Create New User Account


Logged in from


An infrastructure for user acount authorization and file access control is available. Each request is matched against a list of URL path patterns. If the request matches, a Session Ticket is required to access the URL. This Session Ticket should be present as a CGI parameter or Cookie, eg:

Cookie: CGIscriptorSESSION=<value>

The example implementation stores Session Tickets as files in a local directory. To create Session Tickets, a Login request must be given with a LOGIN=<value> CGI parameter, a user name and a (doubly hashed) password. The user name and (singly hashed) password are stored in a PASSWORD ticket with the same name as the user account (name cleaned up for security). There is a Tutorial of the authorization application.

The example session model implements 3 functions:

  1. Login
    The password is hashed with the user name and server side salt, and then hashed with a random salt. Client and Server both perform these actions and the Server only grants access if results are the same. The server side only stores the password hashed with the user name and server side salt. Neither the plain password, nor the hashed password is ever exchanged. Only values hashed with the one-time salt are exchanged.
  2. Session
    For every access to a restricted URL, the Session Ticket is checked before access is granted. There are three session modes. The first uses a fixed Session Ticket that is stored as a cookie value in the browser (actually, as a sessionStorage value). The second uses only the IP address at login to authenticate requests. The third is a Challenge mode, where the client has to calculate the value of the next one-time Session Ticket from a value derived from the password and a random string.
  3. Password Change
    A new password is hashed with the user name and server side salt, and then encrypted (XORed) with the old password hashed with the user name and salt. That value is exchanged and XORed with the stored old hashed(salt+password+username). Again, the stored password value is never exchanged unencrypted.


The session authentication mechanism is based on the exchange of ticket identifiers. A ticket identifier is just a string of characters, a name or a random 64 character hexadecimal string. Authentication is based on a (password derived) shared secret and the ability to calculate ticket identifiers from this shared secret. Ticket identifiers should be "safe" filenames (except user names). At the server side, there are four types of tickets:

All tickets can have an expiration date in the form of a time duration from creation, in seconds, minutes, hours, or days (+duration[smhd]). An absolute time can be given in seconds since the epoch of the server host. Accounts can include a maximal lifetime for session tickets (MaxLifetime).

A Login page should create a LOGIN ticket file locally and send a server specific salt, a Random salt, and a LOGIN ticket identifier. The server side compares the username and hashed password, actually hashed(hashed(password+serversalt)+Random salt) from the client with the values it calculates from the stored Random salt from the LOGIN ticket and the hashed(password+serversalt) from the PASSWORD ticket. If successful, a new SESSION ticket is generated as a (double) hash sum of the LOGIN ticket and the stored password, i.e. LoginTicket = hashed(hashed(password+serversalt)+REMOTE_HOST+Random salt) and SessionTicket = hashed(hashed(LoginTicket).LoginTicket). This SESSION ticket should also be generated by the client and stored as sessionStorage and cookie values as needed. The Username, IP address and Path are available as $LoginUsername, $LoginIPaddress, and $LoginPath, respectively.

The CHALLENGE protocol stores the single hashed version of the SESSION tickets. However, this value is not exchanged, but kept secret in the JavaScript sessionStorage object. Instead, every page returned from the server will contain a one-time Challenge value ($CHALLENGETICKET) which has to be hashed with the stored value to return the current ticket id string.

In the current example implementation, all random values are created as full, 256 bit SHA256 hash values (Hex strings) of 64 bytes read from /dev/urandom.


A limited level of authorization tuning is build into the login system. Each account file (PASSWORD ticket file) can contain a number of Capabilities lines. These control special priveliges. The Capabilities can be checked inside the HTML pages as part of the ticket information. Two privileges are handled internally: CreateUser and VariableREMOTE_ADDR. CreateUser allows the logged in user to create a new user account. With VariableREMOTE_ADDR, the session of the logged in user is not limited to the Remote IP address from which the inital log-in took place. Sessions can hop from one apparant (proxy) IP address to another, e.g., when using Tor. Any IPaddress patterns given in the PASSWORD ticket file remain in effect during the session. For security reasons, the VariableREMOTE_ADDR capability is only effective if the session type is CHALLENGE.

Security considerations with Session tickets

For strong security, please use end-to-end encryption. This can be achieved using a VPN (Virtual Private Network), SSH tunnel, or a HTTPS capable server with OpenSSL. The session ticket system of CGIscriptor.pl is intended to be used as a simple authentication mechanism WITHOUT END-TO-END ENCRYPTION. The authenticating mechanism tries to use some simple means to protect the authentication process from eavesdropping. For this it uses a secure hash function, SHA256. For all practial purposes, it is impossible to "decrypt" a SHA256 sum. But this login scheme is only as secure as your browser. Which, in general, is not very secure.

Humans tend to reuse passwords. A compromise of a site running CGIscriptor.pl could therefore lead to a compromise of user accounts at other sites. Therefore, plain text passwords are never stored, used, or exchanged. Instead, a server site salt value is "encrypted" with the plain password and user name. Actually, all are concatenated and hashed with a one-way secure hash function (SHA256) into a single string. Whenever the word "password" is used, this hash sum is meant. Note that the salts are generated from /dev/urandom. You should check whether the implementation of /dev/urandom on your platform is secure before relying on it. This might be a problem when running CGIscriptor under Cygwin on MS Windows.
Note: no attempt is made to slow down the password hash, so bad passwords can be cracked by brute force

As the (hashed) passwords are all that is needed to identify at the site, these should not be stored in this form. A site specific passphrase can be entered as an environment variable ($ENV{'CGIMasterKey'}). This phrase is hashed with the server site salt and the result is hashed with the user name and then XORed with the password when it is stored. Also, to detect changes to the account (PASSWORD) and session tickets, a (HMAC) hash of some of the contents of the ticket with the server salt and CGIMasterKey is stored in each ticket.

Creating a valid (hashed) password, encrypt it with the CGIMasterKey and construct a signature of the ticket are non-trivial. This has to be redone with every change of the ticket file or CGIMasterKey change. CGIscriptor can do this from the command line with the command:

perl CGIscriptor.pl --managelogin salt=Private/.Passwords/SALT \
  masterkey='Sherlock investigates oleander curry in Bath' \
  password='There is no password like more password' \
CGIscriptor will exit after this command with the first option being --managelogin. Options have the form: When the value of an option is a existing file path, the first line of that file is used. Options are followed by one or more paths plus names of existing ticket files. Each password option is only used for a single ticket file. It is most definitely a bad idea to use a password that is identical to an existing filepath, as the file will be read instead. Be aware that the name of the file should be a cleaned up version of the Username.This will not be checked.

For the authentication and a change of password, the (old) password is used to "encrypt" a random one-time token or the new password, respectively. For authentication, decryption is not needed, so a secure hash function (SHA256) is used to create a one-way hash sum "encryption". A new password must be decrypted. New passwords are encryped by XORing them with the old password.

Strong Passwords: It is so easy

If you only could see what you are typing

Your password might be vulnerable to brute force guessing. Protections against such attacks are costly in terms of code complexity, bugs, and execution time. However, there is a very simple and secure counter measure. See the XKCD comic. The phrase, There is no password like more password would be both much easier to remember, and still stronger than h4]D%@m:49, at least before this phrase was pasted as an example on the Internet.
For the procedures used at this site, a basic computer setup can check in the order of a billion passwords per second. You need a password (or phrase) strength in the order of 56 bits to be a little secure (one year on a single computer). One of the largest network in the world, Bitcoin mining, can check some 12 terahashes per second (June 2012). This corresponds to checking 6 times 1012 passwords per second. It would take a passwords strength of ~68 bits to keep the equivalent of the Bitcoin computer network occupied for around a year before it found a match.
Please be so kind and add the name of your favorite flower, dish, fictional character, or small town to your password. Say, Oleander, Curry, Sherlock, or Bath, UK (each adds ~12 bits) or even the phrase Sherlock investigates oleander curry in Bath (adds > 56 bits, note that oleander is poisonous, so do not try this curry at home). That would be more effective than adding a thousand rounds of encryption.
Typing long passwords without seeing what you are typing is problematic. So a button should be included to make password visible.

Man in the Middle attack

The example Login page is vulnerable to a Man-in-the-Middle (MITM) attack. One fundamental weakness of the implemented procedure is that the Client obtains the code to encrypt the passwords from the server. It is the JavaScript code in the HTML pages. An attacker who could place herself between Server and Client, a man in the middle attack (MITM), could change the code to reveal the plaintext password and other information. There is no real protection against this attack without end-to-end encryption and authentication. A solution for the MITM attack problem to protect at least the password input would be to run a trusted copy of the web page from local storage to handle password input. An example of such a solution has been implemented for IPADDRESS sessions and plain SESSION ticket only. This Login.html page has four comment lines saying:
UNCOMMENT for use in a local version of the Private/Login.html web page.
If you save this Login page and follow the instructions in these comments, you will be able to load the page from local storage in your browser and log in at the designated web site. It is not (yet) possible to set the required session storage inside the browser, so this method only works for IPADDRESS sessions and plain SESSION tickets, not for the CHALLENGE sessions.