1CGI::Session::Tutorial(U3s)er Contributed Perl DocumentatCiGoIn::Session::Tutorial(3)
2
3
4
6 CGI::Session::Tutorial - Extended CGI::Session manual
7
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
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
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
574 For support and licensing see CGI::Session
575
576
577
578perl v5.8.8 2006-11-24 CGI::Session::Tutorial(3)