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,
20       Section 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
25       solutions.
26
27   COOKIE
28       Cookie is a piece of text-information that a web server is entitled to
29       place in the user's hard disk, assuming a user agent (such as Internet
30       Explorer, Mozilla, etc) is compatible with the specification. After the
31       cookie is placed, user agents are required to send these cookies back
32       to the server as part of the HTTP request. This way the server
33       application ( CGI, for example ) will have a way of relating previous
34       requests by the same user agent, thus overcoming statelessness of HTTP.
35
36       Although HTTP Cookies seem to be promising solution for the
37       statelessness of HTTP, they do carry certain limitations, such as
38       limited number of cookies per domain and per user agent and limited
39       size on each cookie. User Agents are required to store at least 300
40       cookies at a time, 20 cookies per domain and allow 4096 bytes of
41       storage for each cookie. They also rise several Privacy and Security
42       concerns, the lists of which can be found on the sections 6-"Privacy"
43       and 7-"Security Considerations" of RFC 2965.
44
45   QUERY STRING
46       Query string is a string appended to URL following a question mark (?)
47       such as:
48
49           http://my.dot.com/login.cgi?user=sherzodr;password=top-secret
50
51       As you probably guessed, it can also help you pass state information
52       from a click to another, but how secure is it do you think, considering
53       these URLs tend to get cached by most of the user agents and also
54       logged in the servers access log, to which everyone can have access.
55
56   HIDDEN FIELDS
57       Hidden field is another alternative to using query strings and they
58       come in two flavors: hidden fields used in POST methods and the ones in
59       GET. The ones used in GET methods will turn into a true query strings
60       once submitted, so all the disadvantages of QUERY_STRINGs apply.
61       Although POST requests do not have limitations of its sister-GET, the
62       pages that hold them get cached by Web browser, and are available
63       within the source code of the page (obviously). They also become
64       unwieldily to manage when one has oodles of state information to keep
65       track of ( for instance, a shopping cart or an advanced search engine).
66
67       Query strings and hidden fields are also lost easily by closing the
68       browser, or by clicking the browser's "Back" button.
69
70   SERVER SIDE SESSION MANAGEMENT
71       This technique is built upon the aforementioned technologies plus a
72       server-side storage device, which saves the state data on the server
73       side. Each session has a unique id associated with the data in the
74       server. This id is also associated with the user agent either in the
75       form of a HTTP Cookie, a QUERY_STRING, hidden field or any combination
76       of the above. This is necessary to make the connection with the client
77       and his data.
78
79       Advantages:
80
81       ·   We no longer need to depend on User Agent constraints in cookie
82           size.
83
84       ·   Sensitive data no longer need to be traveling across the network at
85           each request (which is the case with query strings, cookies and
86           hidden fields). The only thing that travels is the unique id
87           generated for the session (5767393932698093d0b75ef614376314, for
88           instance), which should make no sense to third parties.
89
90       ·   User will not have sensitive data stored in his/her computer in
91           unsecured file (which is a cookie file).
92
93       ·   It's possible to handle very big and even complex data structures
94           transparently (which HTTP Cookies do not handle).
95
96       That's what CGI::Session is all about - implementing server side
97       session management. Now is a good time to get feet wet.
98

PROGRAMMING STYLE

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

SECURITY

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

LICENSING

563       For support and licensing see CGI::Session
564
565
566
567perl v5.12.3                      2008-07-16         CGI::Session::Tutorial(3)
Impressum