Corrected documentation
[CGIscriptor.git] / Private / manual.html
blob51a60574dca38faeb2df47cb10876abad38f04db
1 <html>
2 <head>
3 <title>
4 Private data
5 </title>
6 <script type="text/javascript">
7 <SCRIPT TYPE="text/ssperl" SRC="./JavaScript/PlainPage.js"></SCRIPT>
8 </script>
9 </head>
10 <body>
11 <p>
12 <table width='100%'><tr>
13 <td style='text-align: left'><a href="/index.html">Home</a></td>
14 <td style='text-align: right'><a href="?LOGOUT">Logout</a></td>
15 </tr></table>
16 </p>
17 <p ALIGN=RIGHT><a href="ChangePassword.html">Change Password</a><br />
18 <a href="CreateUser.html">Create New User Account</a>
19 </p>
20 <h1 align=CENTER>Manual</h1>
21 <p align=CENTER>Logged in from <script type="text/ssperl" CGI='$LOGINIPADDRESS="" $LOGINPATH=""'>"$LOGINIPADDRESS $LOGINPATH"</script></p>
22 <p align=CENTER><form method=GET action="index.html">
23 <p align=CENTER><input type="submit" value="Go back to Private home page" /></p>
24 </form>
25 </p>
28 <A NAME="SESSIONTICKETS"><H2 ALIGN="CENTER">SERVER SIDE SESSIONS AND ACCESS CONTROL (LOGIN)</H2></A>
29 <p>
30 An infrastructure for user acount authorization and file access control
31 is available. Each request is matched against a list of URL path patterns.
32 If the request matches, a Session Ticket is required to access the URL.
33 This Session Ticket should be present as a CGI parameter or Cookie, eg:
34 </p>
35 <p>
36 CGI: SESSIONTICKET=&lt;value&gt;<br />
37 Cookie: CGIscriptorSESSION=&lt;value&gt;</p>
38 <p>
39 The example implementation stores Session Tickets as files in a local
40 directory. To create Session Tickets, a Login request must be given
41 with a LOGIN=&lt;value&gt; CGI parameter, a user name and a (doubly hashed)
42 password. The user name and (singly hashed) password are stored in a
43 PASSWORD ticket with the same name as the user account (name cleaned up
44 for security). There is a <a href="/PrivateTutorial.html">Tutorial of the authorization
45 application</a>.
46 </p>
47 <p>
48 The example session model implements 3 functions:
49 <ol>
50 <li>Login<br />
51 The password is hashed with the user name and server side salt, and then
52 hashed with a random salt. Client and Server both perform these actions
53 and the Server only grants access if results are the same. The server
54 side only stores the password hashed with the user name and
55 server side salt. Neither the plain password, nor the hashed password is
56 ever exchanged. Only values hashed with the one-time salt are exchanged.
57 </li>
58 <li>Session<br />
59 For every access to a restricted URL, the Session Ticket is checked before
60 access is granted. There are three session modes. The first uses a fixed
61 Session Ticket that is stored as a cookie value in the browser (actually,
62 as a sessionStorage value). The second uses only the IP address at login
63 to authenticate requests. The third
64 is a Challenge mode, where the client has to calculate the value of the
65 next one-time Session Ticket from a value derived from the password and
66 a random string.
67 </li>
68 <li>Password Change<br />
69 A new password is hashed with the user name and server side salt, and
70 then encrypted (XORed)
71 with the old password hashed with the user name and salt. That value is
72 exchanged and XORed with the stored old hashed(salt+password+username).
73 Again, the stored password value is never exchanged unencrypted.
74 </li>
75 </ol>
76 </p>
77 <H3 ALIGN="CENTER">Implementation</H3>
78 <p>
79 The session authentication mechanism is based on the exchange of ticket
80 identifiers. A ticket identifier is just a string of characters, a name
81 or a random 64 character hexadecimal string. Authentication is based
82 on a (password derived) shared secret and the ability to calculate ticket
83 identifiers from this shared secret. Ticket identifiers should be
84 "safe" filenames (except user names). At the server side, there are four
85 types of tickets:
86 <ul>
87 <li>PASSWORD: User account descriptors, including a user name and password</li>
88 <li>LOGIN: Temporary anonymous tickets used during login</li>
89 <li>IPADDRESS: Authentication tokens that allow access based on the IP address of the request</li>
90 <li>SESSION: Reusable authentication tokens</li>
91 <li>CHALLENGE: One-time authentication tokens</li>
92 </ul>
93 All tickets can have an expiration date in the form of a time duration
94 from creation, in seconds, minutes, hours, or days (<em>+duration</em>[smhd]).
95 An absolute time can be given in seconds since the epoch of the server host.
96 Accounts can include a maximal lifetime for session tickets (MaxLifetime).
97 </p>
98 <p>
99 A Login page should create a LOGIN ticket file locally and send a
100 server specific salt, a Random salt, and a LOGIN ticket
101 identifier. The server side compares the username and hashed password,
102 actually hashed(hashed(password+username+serversalt)+ REMOTE_ADDR + Random salt)
103 from the client with the values it calculates from the stored Random salt from
104 the LOGIN ticket and the hashed(password+username+serversalt) from the
105 PASSWORD ticket. If successful, a new SESSION ticket is generated as a (double)
106 hash sum of the LOGIN ticket and the stored password, i.e.
107 LoginTicket = hashed(hashed(password+username+serversalt)+Random salt) and
108 SessionTicket = hashed(hashed(LoginTicket).LoginTicket).
109 This SESSION ticket should also be generated by the client and stored as
110 sessionStorage and cookie values as needed. The Username, IP address and
111 Path are available as $LoginUsername, $LoginIPaddress, and $LoginPath,
112 respectively.
113 </p>
115 The CHALLENGE protocol stores the single hashed version of the SESSION tickets.
116 However, this value is not exchanged, but kept secret in the JavaScript
117 <em>sessionStorage</em> object. Instead, every page returned from the
118 server will contain a one-time Challenge value ($CHALLENGETICKET) which
119 has to be hashed with the stored value to return the current ticket
120 id string.
121 </p>
123 In the current example implementation, all random values are created as
124 full, 256 bit SHA256 hash values (Hex strings) of 64 bytes read from
125 /dev/urandom.
126 </p>
128 <H3 ALIGN="CENTER">Authorization</H3>
130 A limited level of authorization tuning is build into the login system.
131 Each account file (PASSWORD ticket file) can contain a number of
132 <em>Capabilities</em> lines. These control special priveliges. The
133 Capabilities can be checked inside the HTML pages as part of the
134 ticket information. Two privileges are handled internally:
135 <em>CreateUser</em> and <em>VariableREMOTE_ADDR</em>.
136 <em>CreateUser</em> allows the logged in user to create a new user account.
137 With <em>VariableREMOTE_ADDR</em>, the session of the logged in user is
138 not limited to the Remote IP address from which the inital log-in took
139 place. Sessions can hop from one apparant (proxy) IP address to another,
140 e.g., when using <a href="https://www.torproject.org/">Tor</a>. Any
141 IPaddress patterns given in the PASSWORD ticket file remain in effect
142 during the session. For security reasons, the <em>VariableREMOTE_ADDR</em>
143 capability is only effective if the session type is <em>CHALLENGE</em>.
144 </p>
146 <H3 ALIGN="CENTER">Security considerations with Session tickets</H3>
148 For strong security, please use end-to-end encryption. This can be
149 achieved using a VPN (Virtual Private Network), SSH tunnel, or a HTTPS
150 capable server with OpenSSL. The session ticket system of CGIscriptor.pl
151 is intended to be used as a simple authentication mechanism WITHOUT
152 END-TO-END ENCRYPTION. The authenticating mechanism tries to use some
153 simple means to protect the authentication process from eavesdropping.
154 For this it uses a secure hash function, SHA256. For all practial purposes,
155 it is impossible to "decrypt" a SHA256 sum. But this login scheme is
156 only as secure as your browser. Which, in general, is not very secure.
157 </p>
159 Humans tend to reuse passwords. A compromise of a site running
160 CGIscriptor.pl could therefore lead to a compromise of user accounts at
161 other sites. Therefore, plain text passwords are never stored, used, or
162 exchanged. Instead, a server site salt value is "encrypted" with
163 the plain password and user name. Actually, all are concatenated and hashed
164 with a one-way secure hash function (SHA256) into a single string.
165 Whenever the word "password" is used, this hash sum is meant. Note that
166 the salts are generated from /dev/urandom. You should check whether the
167 implementation of /dev/urandom on your platform is secure before
168 relying on it. This might be a problem when running CGIscriptor under
169 Cygwin on MS Windows.<br />
170 <em>Note: no attempt is made to slow down the password hash, so bad
171 passwords can be cracked by brute force</em>
172 </p>
174 As the (hashed) passwords are all that is needed to identify at the site,
175 these should not be stored in this form. A site specific passphrase
176 can be entered as an environment variable ($ENV{'CGIMasterKey'}). This
177 phrase is hashed with the server site salt and the result is hashed with
178 the user name and then XORed with the password when it is stored. Also, to
179 detect changes to the account (PASSWORD) and session tickets, a
180 (HMAC) hash of some of the contents of the ticket with the server salt and
181 CGIMasterKey is stored in each ticket.
182 </p>
184 Creating a valid (hashed) password, encrypt it with the CGIMasterKey and
185 construct a signature of the ticket are non-trivial. This has to be redone
186 with every change of the ticket file or CGIMasterKey change. CGIscriptor
187 can do this from the command line with the command:
188 <pre>
189 perl CGIscriptor.pl --managelogin salt=Private/.Passwords/SALT \
190 masterkey='Sherlock investigates oleander curry in Bath' \
191 password='There is no password like more password' \
192 admin
193 </pre>
194 CGIscriptor will exit after this command with the first option being
195 <em>--managelogin</em>. Options have the form:
196 <ul>
197 <li>salt=[file or string]<br />Server salt value to use io the value
198 stored in the ticket file. Will replace the stored value if a new
199 password is given. If you change the server salt, you have to
200 reset all the passwords. There is <em>absolutely no</em> procedure known
201 to recover plaintext passwords, except asking the account holders.
202 You are strongly adviced to make a backup before you apply such a change</li>
203 <li>masterkey=[file or string]<br />CGIMasterKey used to read and decrypt
204 the ticket</li>
205 <li>newmasterkey=[file or string]<br />CGIMasterKey used to encrypt, sign,
206 and write the ticket. Defaults to the masterkey. If you change
207 the masterkey, you will have to reset all the accounts. You are strongly
208 adviced to make a backup before you apply such a change</li>
209 <li>password=[file or string]<br />New plaintext password</li>
210 </ul>
211 When the value of an option is a existing file path, the first line of
212 that file is used. Options are followed by one or more paths plus names
213 of existing ticket files. Each password option is only used for a single
214 ticket file. It is most definitely a bad idea to use a password that is
215 identical to an existing filepath, as the file will be read instead. Be
216 aware that the name of the file should be a cleaned up version of the
217 Username.This will not be checked.
218 </p>
220 For the authentication and a change of password, the (old) password
221 is used to "encrypt" a random one-time token or the new password,
222 respectively. For authentication, decryption is not needed, so a secure
223 hash function (SHA256) is used to create a one-way hash sum "encryption".
224 A new password must be decrypted. New passwords are encryped by XORing
225 them with the old password.
226 </p>
228 There are four default accounts present: <em>testip, test, testchallenge</em>, and
229 <em>admin</em>. The former three have password <em>testing</em>, the latter has password
230 <em>There is no password like more password</em>. The <em>admin</em>
231 account is disabled by default. You can enable it with a new password
232 using the <tt>--managelogin</tt> option. All four accounts are limited to local
233 (<em>localhost</em>) requests. When present, <em>testip, test</em>, and
234 <em>testchallenge</em> are reactivated with the default password <em>testing</em>
235 whenever a new SALT is automatically generated. It is adviced that the <em>test</em>
236 accounts are removed when setting up a site.
237 </p>
239 <h3 align=CENTER>Strong Passwords: It is so easy</h3>
240 <p align=CENTER><em>If you only could see what you are typing</em></p>
241 <p >
242 Your password might be vulnerable to
243 <a href="https://en.wikipedia.org/wiki/Brute_force_attack">
244 <em>brute force</em></a> guessing. Protections against such attacks are
245 costly in terms of code complexity, bugs, and execution time.
246 However, there is a very simple and secure counter measure. See the
247 <a href="http://xkcd.com/936/" target="_blank">XKCD comic</a>. The phrase,
248 <em>There is no password like more password</em> would
249 be both much easier to remember, and still stronger than
250 <em>h4]D%@m:49</em>, at least before this phrase was pasted as an example
251 on the Internet.<br />
252 For the procedures used at this site, a basic computer setup can check
253 in the order of a billion passwords per second. You need a password (or
254 phrase) strength in the order of 56 bits to be a little secure (one year
255 on a single computer). One of the largest network in the world, Bitcoin
256 mining, can check some 12 terahashes per second (June 2012). This
257 corresponds to checking 6 times 10<sup>12</sup> passwords per second.
258 It would take a passwords strength of ~68 bits to keep the equivalent of
259 the Bitcoin computer network occupied for around a year before it found
260 a match.<br />
261 Please be so kind and add the name of your favorite flower, dish,
262 fictional character, or small town to your password. Say,
263 <em>Oleander</em>, <em>Curry</em>, <em>Sherlock</em>, or <em>Bath</em>, UK
264 (each adds ~12 bits) or even the phrase <em>Sherlock investigates
265 oleander curry in Bath</em> (adds &gt; 56 bits, note that oleander is
266 <em>poisonous</em>, so do not try this curry at home). That would be more
267 effective than adding a thousand rounds of encryption. <br />
268 Typing long passwords without seeing what you are typing is problematic.
269 So a button should be included to make password visible.
270 </p>
271 <h3 align=CENTER>Man in the Middle attack</h3>
273 The example Login page is vulnerable to a Man-in-the-Middle (MITM) attack.
274 One fundamental weakness of the implemented procedure is that the Client obtains
275 the code to encrypt the passwords from the server. It is the JavaScript
276 code in the HTML pages. An attacker who could place herself between Server
277 and Client, a man in the middle attack (MITM), could change the code to
278 reveal the plaintext password and other information. There is no real
279 protection against this attack without end-to-end encryption and
280 authentication.
282 A simple, but rather cumbersome, way to check for such
283 attacks would be to store known good copies of the pages (downloaded
284 with a browser or automatically with <em>curl</em> or <em>wget</em>) and
285 then use other tools to download new pages at random intervals and compare
286 them to the old pages. For instance, the following line would remove the
287 variable ticket codes and give a fixed SHA256 sum for the original
288 <em>Login.html</em> page+code:
289 <pre>
290 curl http://localhost:8080/Private/index.html | sed 's/=\"[a-z0-9]\{64\}\"/=""/g' | shasum -a 256
291 </pre>
292 A simple <em>diff</em> command between old and new files should give
293 only differences in half a dozen lines, where only hexadecimal salt
294 values will actually differ.
295 </p>
297 A sort of solution for the MITM attack problem that <em>might</em> protect at
298 least the plaintext password would be to run a trusted web
299 page from local storage to handle password input. The solution would be
300 to add a hidden iFrame tag loading the untrusted page from the URL and
301 extract the needed ticket and salt values. Then run the stored, trusted,
302 code with these values. It is not (yet) possible to set the
303 required session storage inside the browser, so this method only works
304 for IPADDRESS sessions and plain SESSION tickets. There are many security
305 problems with this "solution".
306 </p>
308 If you are able to ascertain the integrity of the login page using any
309 of the above methods, you can check whether the IP address seen by the
310 login server is indeed the IP address of your computer. The IP address
311 of the REMOTE_HOST (your visible IP address) is part of the login
312 "password". It is stored in the login page as a CLIENTIPADDRESS. It can
313 can be inspected by clicking the "Check IP address" box. Provided the
314 MitM attacker cannot spoof your IP address, you can ensure that the login
315 server sees your IP address and not that of an attacker.
316 </p>
317 </body>
318 </html>