1CGI::Session::Tutorial(U3s)er Contributed Perl DocumentatCiGoIn::Session::Tutorial(3)
2
3
4

NAME

6       CGI::Session::Tutorial - Extended CGI::Session manual
7

STATE MAINTENANCE OVERVIEW

9       Since HTTP is a stateless protocol, each subsequent click to a web site
10       is treated as new request by the Web server. The server does not relate
11       a visit with a previous one, thus all the state information from the
12       previous requests are lost. This makes creating such applications as
13       shopping carts, web sites requiring users to authenticate, impossible.
14       So people had to do something about this despair situation HTTP was
15       putting us in.
16
17       For our rescue come such technologies as HTTP Cookies and QUERY_STRINGs
18       that help us save the users' session for a certain period. Since HTTP
19       Cookies and QUERY_STRINGs alone cannot take us too far (RFC 2965, Sec‐
20       tion 5, "Implementation Limitations"), several other libraries have
21       been developed to extend their capabilities and promise a more reliable
22       solution. CGI::Session is one of them.
23
24       Before we discuss this library, let's look at some alternative solu‐
25       tions.
26
27       COOKIE
28
29       Cookie is a piece of text-information that a web server is entitled to
30       place in the user's hard disk, assuming a user agent (such as Internet
31       Explorer, Mozilla, etc) is compatible with the specification. After the
32       cookie is placed, user agents are required to send these cookies back
33       to the server as part of the HTTP request. This way the server applica‐
34       tion ( CGI, for example ) will have a way of relating previous requests
35       by the same user agent, thus overcoming statelessness of HTTP.
36
37       Although HTTP Cookies seem to be promising solution for the stateless‐
38       ness of HTTP, they do carry certain limitations, such as limited number
39       of cookies per domain and per user agent and limited size on each
40       cookie. User Agents are required to store at least 300 cookies at a
41       time, 20 cookies per domain and allow 4096 bytes of storage for each
42       cookie. They also rise several Privacy and Security concerns, the lists
43       of which can be found on the sections 6-"Privacy"  and 7-"Security Con‐
44       siderations" of RFC 2965.
45
46       QUERY STRING
47
48       Query string is a string appended to URL following a question mark (?)
49       such as:
50
51           http://my.dot.com/login.cgi?user=sherzodr;password=top-secret
52
53       As you probably guessed, it can also help you pass state information
54       from a click to another, but how secure is it do you think, considering
55       these URLs tend to get cached by most of the user agents and also
56       logged in the servers access log, to which everyone can have access.
57
58       HIDDEN FIELDS
59
60       Hidden field is another alternative to using query strings and they
61       come in two flavors: hidden fields used in POST methods and the ones in
62       GET. The ones used in GET methods will turn into a true query strings
63       once submitted, so all the disadvantages of QUERY_STRINGs apply.
64       Although POST requests do not have limitations of its sister-GET, the
65       pages that hold them get cached by Web browser, and are available
66       within the source code of the page (obviously). They also become
67       unwieldily to manage when one has oodles of state information to keep
68       track of ( for instance, a shopping cart or an advanced search engine).
69
70       Query strings and hidden fields are also lost easily by closing the
71       browser, or by clicking the browser's "Back" button.
72
73       SERVER SIDE SESSION MANAGEMENT
74
75       This technique is built upon the aforementioned technologies plus a
76       server-side storage device, which saves the state data on the server
77       side. Each session has a unique id associated with the data in the
78       server. This id is also associated with the user agent either in the
79       form of a HTTP Cookie, a QUERY_STRING, hidden field or any combination
80       of the above. This is necessary to make the connection with the client
81       and his data.
82
83       Advantages:
84
85       ·   We no longer need to depend on User Agent constraints in cookie
86           size.
87
88       ·   Sensitive data no longer need to be traveling across the network at
89           each request (which is the case with query strings, cookies and
90           hidden fields). The only thing that travels is the unique id gener‐
91           ated for the session (5767393932698093d0b75ef614376314, for
92           instance), which should make no sense to third parties.
93
94       ·   User will not have sensitive data stored in his/her computer in
95           unsecured file (which is a cookie file).
96
97       ·   It's possible to handle very big and even complex data structures
98           transparently (which HTTP Cookies do not handle).
99
100       That's what CGI::Session is all about - implementing server side ses‐
101       sion management. Now is a good time to get feet wet.
102

PROGRAMMING STYLE

104       Server side session management system might be seeming awfully convo‐
105       luted if you have never dealt with it. Fortunately, with CGI::Session
106       all the complexity is handled by the library transparently. This sec‐
107       tion of the manual can be treated as an introductory tutorial to  both
108       logic behind session management, and to CGI::Session programming style.
109
110       All applications making use of server side session management rely on
111       the following pattern of operation regardless of the way the system is
112       implemented:
113
114       1   Check if the user has session cookie dropped in his computer from
115           previous request
116
117       2   If the cookie does not exist, create a new session identifier, and
118           drop it as cookie to the user's computer.
119
120       3   If session cookie exists, read the session ID from the cookie and
121           load any previously saved session data from the server side stor‐
122           age. If session had any expiration date set it's useful to re-drop
123           the same cookie to the user's computer so its expiration time will
124           be reset to be relative to user's last activity time.
125
126       4   Store any necessary data in the session that you want to make
127           available for the next HTTP request.
128
129       CGI::Session will handle all of the above steps. All you have to do is
130       to choose what to store in the session.
131
132       GETTING STARTED
133
134       To make CGI::Session's functionality available in your program do
135       either of the following somewhere on top of your program file:
136
137           use CGI::Session;
138           # or
139           require CGI::Session;
140
141       Whenever you're ready to create a new session in your application, do
142       the following:
143
144           $session = new CGI::Session() or die CGI::Session->errstr;
145
146       Above line will first try to re-initialize an existing session by con‐
147       sulting cookies and necessary QUERY_STRING parameters. If it fails will
148       create a brand new session with a unique ID, which is normally called
149       session ID, SID for short, and can be accessed through id() - object
150       method.
151
152       We didn't check for any session cookies above, did we? No, we didn't,
153       but CGI::Session did. It looked for a cookie called "CGISESSID", and if
154       it found it tried to load existing session from server side storage
155       (file in our case). If cookie didn't exist it looked for a QUERY_STRING
156       parameter called "CGISESSID". If all the attempts to recover session ID
157       failed, it created a new session.
158
159       NOTE: For the above syntax to work as intended your application needs
160       to have write access to your computer's TEMPDIR folder, which is usu‐
161       ally /tmp in UNIX. If it doesn't, or if you wish to store this applica‐
162       tion's session files in a different place, you may pass the third argu‐
163       ment like so:
164
165           $session = new CGI::Session(undef, undef, {Directory=>'../tmp/sessions'});
166
167       Now it will store all the newly created sessions in (and will attempt
168       to initialize requested sessions from) that folder. Don't worry if the
169       directory hierarchy you want to use doesn't already exist. It will be
170       created for you. For details on how session data are stored refer to
171       CGI::Session::Driver::file, which is the default driver used in our
172       above example.
173
174       There is one small, but very important thing your application needs to
175       perform after creating CGI::Session object as above. It needs to drop
176       Session ID as an HTTP cookie into the user's computer. CGI::Session
177       will use this cookie to identify the user at his/her next request and
178       will be able to load his/her previously stored session data.
179
180       To make sure CGI::Session will be able to read your cookie at next
181       request you need to consult its "name()" method for cookie's suggested
182       name:
183
184           $cookie = $query->cookie( -name   => $session->name,
185                                     -value  => $session->id );
186           print $query->header( -cookie=>$cookie );
187
188       "name()" returns "CGISESSID" by default. If you prefer a different
189       cookie name, you can change it as easily too, but you have to do it
190       before CGI::Session object is created:
191
192           CGI::Session->name("SID");
193           $session = new CGI::Session();
194
195       Baking the cookie wasn't too difficult, was it? But there is an even
196       easier way to send a cookie using CGI::Session:
197
198           print $session->header();
199
200       The above will create the cookie using CGI::Cookie and will return
201       proper http headers using CGI.pm's CGI method. Any arguments to
202       CGI::Session will be passed to CGI::header().
203
204       Of course, this method of initialization will only work if client is
205       accepting cookies. If not you would have to pass session ID in each URL
206       of your application as QUERY_STRING. For CGI::Session to detect it the
207       name of the parameter should be the same as returned by name():
208
209           printf ("<a href=\"$ENV{SCRIPT_NAME}?%s=%s\">click me</a>", $session->name, $session->id);
210
211       If you already have session id to be initialized you may pass it as the
212       only argument, or the second argument of multi-argument syntax:
213
214           $session = new CGI::Session( $sid );
215           $session = new CGI::Session( "serializer:freezethaw", $sid );
216           $session = new CGI::Session( "driver:mysql", $sid, {Handle=>$dbh} );
217
218       By default CGI::Session uses standard CGI to parse queries and cookies.
219       If you prefer to use a different, but compatible object you can pass
220       that object in place of $sid:
221
222           $cgi     = new CGI::Simple();
223           $session = new CGI::Session ( $cgi );
224           $session = new CGI::Session( "driver:db_file;serializer:storable", $cgi);
225           # etc
226
227       See CGI::Simple
228
229       STORING DATA
230
231       CGI::Session offers param() method, which behaves exactly as CGI.pm's
232       param() with identical syntax. param() is used for storing data in ses‐
233       sion as well as for accessing already stored data.
234
235       Imagine your customer submitted a login form on your Web site. You, as
236       a good host, wanted to remember the guest's name, so you can a) greet
237       him accordingly when he visits your site again, or b) to be helpful by
238       filling out user name part of his login form, so the customer can jump
239       right to the password field without having to type his username again.
240
241           my $name = $cgi->param('username');
242           $session->param('username', $name);
243
244       Notice, we're grabbing username value of the field using CGI.pm's (or
245       another compatible library's) "param()" method, and storing it in ses‐
246       sion using CGI::Session's param() method.
247
248       If you have too many stuff to transfer into session, you may find your‐
249       self typing the above code over and over again. I've done it, and
250       believe me, it gets very boring too soon, and is also error-prone. So
251       we introduced the following handy method:
252
253           $session->save_param(['name']);
254
255       If you wanted to store multiple form fields just include them all in
256       the second list:
257
258           $session->save_param(['name', 'email']);
259
260       If you want to store all the available QUERY_STRING parameters you can
261       omit the arguments:
262
263           $session->save_param();
264
265       See save_param() for more details.
266
267       When storing data in the session you're not limited to strings. You can
268       store arrays, hashes and even most objects. You will need to pass them
269       as references (except objects).
270
271       For example, to get all the selected values of a scrolling list and
272       store it in the session:
273
274           my @fruits = $cgi->param('fruits');
275           $session->param('fruits', \@fruits);
276
277       For parameters with multiple values save_param() will do the right
278       thing too. So the above is the same as:
279
280           $session->save_param($cgi, ['fruits']);
281
282       All the updates to the session data using above methods will not
283       reflect in the data store until your application exits, or $session
284       goes out of scope. If, for some reason, you need to commit the changes
285       to the data store before your application exits you need to call
286       flush() method:
287
288           $session->flush();
289
290       I've written a lot of code, and never felt need for using "flush()"
291       method, since CGI::Session calls this method at the end of each
292       request. There are, however, occasions I can think of one may need to
293       call flush().
294
295       ACCESSING STORED DATA
296
297       There's no point of storing data if you cannot access it. You can
298       access stored session data by using the same param() method you once
299       used to store them. Remember the Username field from the previous sec‐
300       tion that we stored in the session? Let's read it back so we can par‐
301       tially fill the Login form for the user:
302
303           $name = $session->param("name");
304           printf "<input type=\"text\" name=\"name\" value=\"%s\" />", $name;
305
306       To retrieve previously stored @fruits do not forget to de reference it:
307
308           @fruits = @{ $session->param('fruits') };
309
310       Very frequently, you may find yourself having to create pre-filled and
311       pre-selected forms, like radio buttons, checkboxes and drop down menus
312       according to the user's preferences or previous action. With text and
313       textareas it's not a big deal - you can simply retrieve a single param‐
314       eter from the session and hard code the value into the text field. But
315       how would you do it when you have a group of radio buttons, checkboxes
316       and scrolling lists? For this purpose, CGI::Session provides
317       load_param() method, which loads given session parameters to a CGI
318       object (assuming they have been previously saved with save_param() or
319       alternative):
320
321           $session->load_param($cgi, ["fruits"]);
322
323       Now when you say:
324
325           print $cgi->checkbox_group(fruits=>['apple', 'banana', 'apricot']);
326
327       See load_param() for details.
328
329       Generated checkboxes will be pre-filled using previously saved informa‐
330       tion. To see example of a real session-powered application consider
331       http://handalak.com/cgi-bin/subscriptions.cgi
332
333       If you're making use of HTML::Template to separate the code from the
334       skin, you can as well associate CGI::Session object with HTML::Template
335       and access all the parameters from within HTML files. We love this
336       trick!
337
338           $template = new HTML::Template(filename=>"some.tmpl", associate=>$session);
339           print $template->output();
340
341       Assuming the session object stored "first_name" and "email" parameters
342       while being associated with HTML::Template, you can access those values
343       from within your "some.tmpl" file now:
344
345           Hello <a href="mailto:<TMPL_VAR email>"> <TMPL_VAR first_name> </a>!
346
347       See HTML::Template's online manual for details.
348
349       CLEARING SESSION DATA
350
351       You store session data, you access session data and at some point you
352       will want to clear certain session data, if not all. For this purpose
353       CGI::Session provides clear() method which optionally takes one argu‐
354       ment as an arrayref indicating which session parameters should be
355       deleted from the session object:
356
357           $session->clear(["~logged-in", "email"]);
358
359       Above line deletes "~logged-in" and "email" session parameters from the
360       session. And next time you say:
361
362           $email = $session->param("email");
363
364       it returns undef. If you omit the argument to clear(), be warned that
365       all the session parameters you ever stored in the session object will
366       get deleted. Note that it does not delete the session itself. Session
367       stays open and accessible. It's just the parameters you stored in it
368       gets deleted
369
370       See clear() for details.
371
372       DELETING A SESSION
373
374       If there's a start there's an end. If session could be created, it
375       should be possible to delete it from the disk for good:
376
377           $session->delete();
378
379       The above call to delete() deletes the session from the disk for good.
380       Do not confuse it with clear(), which only clears certain session
381       parameters but keeps the session open.
382
383       See delete() for details.
384
385       EXPIRATION
386
387       CGI::Session provides limited means to expire sessions. Expiring a ses‐
388       sion is the same as deleting it via delete(), but deletion takes place
389       automatically. To expire a session, you need to tell the library how
390       long the session would be valid after the last access time. When that
391       time is met, CGI::Session refuses to retrieve the session. It deletes
392       the session and returns a brand new one. To assign expiration ticker
393       for a session, use expire():
394
395           $session->expire(3600);     # expire after 3600 seconds
396           $session->expire('+1h');    # expire after 1 hour
397           $session->expire('+15m');   # expire after 15 minutes
398           $session->expire('+1M');    # expire after a month and so on.
399
400       When session is set to expire at some time in the future, but session
401       was not requested at or after that time has passed it will remain in
402       the disk. When expired session is requested CGI::Session will remove
403       the data from disk, and will initialize a brand new session.
404
405       See expire() for details.
406
407       Before CGI::Session 4.x there was no way of intercepting requests to
408       expired sessions. CGI::Session 4.x introduced new kind of constructor,
409       load(), which is identical in use to new(), but is not allowed to cre‐
410       ate sessions. It can only load them. If session is found to be expired,
411       or session does not exist it will return an empty CGI::Session object.
412       And if session is expired, in addition to being empty, its status will
413       also be set to expired. You can check against these conditions using
414       empty() and is_expired() methods. If session was loaded successfully
415       object returned by "load()" is as good a session as the one returned by
416       "new()":
417
418           $session = CGI::Session->load() or die CGI::Session->errstr;
419           if ( $session->is_expired ) {
420               die "Your session expired. Please refresh your browser to re-start your session";
421           }
422           if ( $session->is_empty ) {
423               $session = $session->new();
424           }
425
426       Above example is worth an attention. Remember, all expired sessions are
427       empty sessions, but not all empty sessions are expired sessions. Fol‐
428       lowing this rule we have to check with "is_expired()" before checking
429       with "is_empty()". There is another thing about the above example.
430       Notice how its creating new session when un existing session was
431       requested? By calling "new()" as an object method! Handy thing about
432       that is, when you call "new()" on a session object new object will be
433       created using the same configuration as the previous object.
434
435       For example:
436
437           $session = CGI::Session->load("driver:mysql;serializer:storable", undef, {Handle=>$dbh});
438           if ( $session->is_expired ) {
439               die "Your session is expired. Please refresh your browser to re-start your session";
440           }
441           if ( $session->is_empty ) {
442               $session = $session->new();
443           }
444
445       Initial $session object was configured with mysql as the driver,
446       storable as the serializer and $dbh as the database handle. Calling "
447       new() " on this object will return an object of the same configuration.
448       So  $session  object returned from " new() " in the above example will
449       use mysql as the driver, storable as the serializer and $dbh as the
450       database handle.
451
452       See is_expired(), is_empty(), load() for details.
453
454       Sometimes it makes perfect sense to expire a certain session parameter,
455       instead of the whole session. I usually do this in my login enabled
456       sites, where after the user logs in successfully, I set his/her
457       "_logged_in" session parameter to true, and assign an expiration ticker
458       on that flag to something like 30 minutes. It means, after 30 idle min‐
459       utes CGI::Session will clear "_logged_in" flag, indicating the user
460       should log in over again. I agree, the same effect can be achieved by
461       simply expiring() the session itself, but by doing this we would loose
462       other session parameters, such as user's shopping cart, session-prefer‐
463       ences and the like.
464
465       This feature can also be used to simulate layered authentication, such
466       as, you can keep the user's access to his/her personal profile informa‐
467       tion for as long as 60 minutes after a successful login, but expire
468       his/her access to his credit card information after 5 idle minutes. To
469       achieve this effect, we will use expire() method again:
470
471           $session->expire(_profile_access, '1h');
472           $session->expire(_cc_access, '5m');
473
474       With the above syntax, the person will still have access to his per‐
475       sonal information even after 5 idle hours. But when he tries to access
476       or update his/her credit card information, he may be displayed a "login
477       again, please" screen.
478
479       See expire() for details.
480
481       This concludes our discussion of CGI::Session programming style. The
482       rest of the manual covers some "SECURITY" issues. Driver specs from the
483       previous manual were moved to CGI::Session::Driver.
484

SECURITY

486       "How secure is using CGI::Session?", "Can others hack down people's
487       sessions using another browser if they can get the session id of the
488       user?", "Are the session ids easy to guess?" are the questions I find
489       myself answering over and over again.
490
491       STORAGE
492
493       Security of the library does in many aspects depend on the implementa‐
494       tion. After making use of this library, you no longer have to send all
495       the information to the user's cookie except for the session id. But,
496       you still have to store the data in the server side. So another set of
497       questions arise, can an evil person get access to session data in your
498       server, even if he does, can he make sense out of the data in the ses‐
499       sion file, and even if he can, can he reuse the information against a
500       person who created that session. As you see, the answer depends on
501       yourself who is implementing it.
502
503       ·   First rule of thumb, do not store users' passwords or other sensi‐
504           tive data in the session, please. If you have to, use one-way
505           encryption, such as md5, or SHA-1-1. For my own experience I can
506           assure you that in properly implemented session-powered Web appli‐
507           cations there is never a need for it.
508
509       ·   Default configuration of the driver makes use of Data::Dumper class
510           to serialize data to make it possible to save it in the disk.
511           Data::Dumper's result is a human readable data structure, which, if
512           opened, can be interpreted easily. If you configure your session
513           object to use either Storable or FreezeThaw as a serializer, this
514           would make it more difficult for bad guys to make sense out of ses‐
515           sion data. But don't use this as the only precaution. Since evil
516           fingers can type a quick program using Storable or FreezeThaw to
517           decipher session files very easily.
518
519       ·   Do not allow anyone to update contents of session files. If you're
520           using default serializer serialized data string needs to be
521           eval()ed to bring the original data structure back to life. Of
522           course, we use Safe to do it safely, but your cautiousness does no
523           harm either.
524
525       ·   Do not keep sessions open for very long. This will increase the
526           possibility that some bad guy may have someone's valid session id
527           at a given time (acquired somehow). To do this use expire() method
528           to set expiration ticker. The more sensitive the information on
529           your Web site is, the sooner the session should be set to expire.
530
531       SESSION IDs
532
533       Session ids are not easily guessed (unless you're using incr ID genera‐
534       tor)! Default configuration of CGI::Session uses Digest::MD5 to gener‐
535       ate random, 32 character long identifier. Although this string cannot
536       be guessed as easily by others, if they find it out somehow, can they
537       use this identifier against the other person?
538
539       Consider the scenario, where you just give someone either via email or
540       an instant messaging a link to a Web site where you're currently logged
541       in. The URL you give to that person contains a session id as part of a
542       query string. If the site was initializing the session solely using
543       query string parameter, after clicking on that link that person now
544       appears to that site as you, and might have access to all of your pri‐
545       vate data instantly.
546
547       Even if you're solely using cookies as the session id transporters,
548       it's not that difficult to plant a cookie in the cookie file with the
549       same id and trick the web browser to send that particular session id to
550       the server. So key for security is to check if the person who's asking
551       us to retrieve a session data is indeed the person who initially cre‐
552       ated the session data.
553
554       One way to help with this is by also checking that the IP address that
555       the session is being used from is always same. However, this turns out
556       not to be practical in common cases because some large ISPs (such as
557       AOL) use proxies which cause each and every request from the same user
558       to come from different IP address.
559
560       If you have an application where you are sure your users' IPs are con‐
561       stant during a session, you can consider enabling an option to make
562       this check:
563
564           use CGI::Session ( '-ip_match' );
565
566       For backwards compatibility, you can also achieve this by setting
567       $CGI::Session::IP_MATCH to a true value.  This makes sure that before
568       initializing a previously stored session, it checks if the ip address
569       stored in the session matches the ip address of the user asking for
570       that session. In which case the library returns the session, otherwise
571       it dies with a proper error message.
572

LICENSING

574       For support and licensing see CGI::Session
575
576
577
578perl v5.8.8                       2006-11-24         CGI::Session::Tutorial(3)
Impressum