<<

STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM Reducing Business Risk using a very short course by Randal L. Schwartz Stonehenge Consulting Services Version 1.2.1 (5/13/99)[S]

Copyright ©1999 by Randal L. Schwartz, Stonehenge Consulting Services, Inc. Page 1 of 1

STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Table of Contents

Introduction 2 Use CGI.pm’s function imports, not object interface ...... 21 What this course is about ...... 3 Reduce duplicated code ...... 22 Keep global variable usage to a minimum...... 23 Part One: Keep global variable usage to a minimum (cont’d)...... 24 using Perl instead of other things 4 Warnings ...... 25 What is Perl? ...... 5 Multiple writers must be coordinated ...... 26 Who uses Perl?...... 6 Use Socket.pm, not sys/socket.ph ...... 27 Purpose of Perl...... 7 Use IO::Socket::INET, not roll-your-own socket stuff ...... 28 Availability ...... 8 Use LWP and Net::*, not roll-your-own standard protocol stuff . . . 29 Support...... 9 Always check return values ...... 30 Books ...... 10 Don’t leave dead children lying about...... 31 Basic concepts ...... 11 Another anti-zombie solution—the “double fork” ...... 32 Some brief explained examples ...... 12 Document your code ...... 33 Perl as Glue ...... 13 Use debugging code, controlled by a global variable ...... 34 Optimized for “90% text, 10% something else” ...... 14 See perlstyle for additional ideas ...... 35 Perl supports “programming in the large” ...... 15 Taint checks ...... 36 Good books and courses available...... 16 Inputs that are tainted...... 37 Tainting is sticky ...... 38 Part Two: Actions that are dangerous...... 39 use Perl correctly 17 Other dangerous actions...... 40 Y2K ...... 18 No need for shells to launch children ...... 41 The only Perl is “Perl version 5” ...... 19 Coding to avoid the shell ...... 42 Use CGI.pm (not cgi-lib.pl)...... 20 Coding to avoid forking...... 43

Page 1 of 2

STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

CGI Security—Hidden fields...... 44 Don't put sensitive data in the GET URL ...... 45 Don’t count on REFERER...... 46 Don't presume anything about the execution environment ...... 47 The HTTP “Username” ...... 48 Don’t use /bin/mail or /bin/mailx to send mail ...... 49 Use a valid return address when sending mail...... 50 Writing to STDERR...... 51 Failures should never reveal internal information ...... 52 Throw away bad books ...... 53 Get good support for advanced technology ...... 54 Conclusion 55 Questions and answers...... 56

Page 2 of 2

STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM Reducing Business Risk using Perl a very short course by Randal L. Schwartz Stonehenge Consulting Services Version 1.2.1 (5/14/99)[S]

Copyright ©1999 by Randal L. Schwartz, Stonehenge Consulting Services, Inc. Page 1 of 56

STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Introduction

Page 2 of 56

STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

What this course is about

¥ “Reducing Business Risk Using Perl” ¥ 1. In order to reduce the risk and uncertainty around your security issues ¥ 2. In order to achieve your business objectives ¥ 3. In order to increase the certainty that your employees will be productive ¥ Question—Do I mean “Use Perl instead of other things” or “Use Perl correctly”? ¥ Answer—Yes! ¥ First half will cover “Why Perl” ¥ Second half will cover “How Perl” ¥ Who are you? Engineers and Engineering Managers that are using (or considering using) Perl for system administration, toolsmithing, web applications, end-user applications, or quality assurance. ¥ What will you get? More educated about motivations for using Perl, as well as the risks of not using Perl effectively.

Page 3 of 56

STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Part One: using Perl instead of other things

Page 4 of 56

STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

What is Perl?

¥ Invented and still owned by Larry Wall (author of rn and patch) ¥ Larry is trained as a linguist, not a computer scientist—understands how people process information ¥ First release, 1987 (older than the Web!) ¥ Available under a zero-cost license ¥ Has been embedded or bundled with commercial products (again, no cost) ¥ Source code is available ¥ Originated in , but ported to many architectures ¥ In particular, the Windows NT/95/98 port has been extended to access nearly all OS functions ¥ And the Mac version likewise ¥ Large user community, estimated at 2 million, with 200 new programmers per day ¥ Not tied to a particular vendor’s idea of “this year’s best scripting language”

Page 5 of 56

STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Who uses Perl?

¥ Stonehenge client list includes: ADP, Allen Bradley (Rockwell Automation), Allied-Signal, American Online, Arco (Anchorage), Boeing (and Boeing Computing Services), Cisco Systems, Cray Research, Dow Chemical, Dynamic Web Enterprises, Genentech, Hewlett-Packard (Corvallis, Cupertino), Intel (Hillsboro, Folsom), Intelsat, Interactive Systems, Lehman Bros., MIPS, Matthew-Bender, Mentor Graphics (UK), Morgan Stanley, Motorola (Austin, Chicago, Phoenix, Fort Worth), NASA/Ames, NASA/JPL (the first real home of Perl :-), Network Equipment Technologies, Nokia, Octel, Pyramid, Qualcomm, Rational Software Corp, SCT Corporation, Shell Systems International, Silicon Graphics, Silicon Systems (Orange County, Santa Cruz), State Farm Insurance, Texaco, Union Bank of Switzerland, United States Army, University of Buffalo (staff), Washington Post "dot Com" (Digital Ink),World Bank ¥ Other notables: Yahoo, Altavista, Dejanews, Filepile, Internet Movie Database, etc etc

Page 6 of 56

STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Purpose of Perl

¥ Data slogging, process management, generic tool box for Unix (“duct-tape of the Internet”1) ¥ Fills the gap between /Java/C++ programming (usually hard and ugly, but fast and unlimited) and shell programming (slow, hard, ugly, and limited)—Perl is easy, kind of ugly, mostly fast, and nearly unlimited ¥ Very High Level Language (code is more dense, therefore faster to code, shorter to debug) ¥ Amazingly much more portable than any C/C++/Java program or shell program ¥ Not a complete replacement for C2 but durn near close ¥ Not for writing distributed proprietary code ¥ Good for one-offs, and long and extensive hacking, and even prototyping eventual C/C++/Java programs ¥ Many features designed to large programs easy

1. Hassan Schroeder of Sun Microsystems, as quoted in http://www.webdeveloper.com/spring96/duke.html 2. “I use C myself, occasionally”—Larry Wall

Page 7 of 56

STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Availability

¥ Everywhere (like Elvis sightings) ¥ Released under the GNU Copyleft, or Larry’s , whichever you like ¥ Source code, and lots more, at any Comprehensive Perl Archive Network (CPAN) site ¥ Nearest CPAN site can be located via http://www.perl.com/CPAN/ ¥ Also on a few CD-ROMs ¥ And O’Reilly Perl Resource Kit (for Unix and Win32 systems) ¥ Also included with many vendors’ systems ¥ Distribution is self-configuring for nearly anything that calls itself Unix and has a C compiler ¥ Non-UNIX binaries available via CPAN—Acorn, Amiga, AOS, AS400, Atari, BeOS, LynxOS, Mac, MPE, MS-DOS, Netware, MVS, OS/2, Plan9, QNX,VOS, VMS, Win32 ¥ Larry has promised that Perl will always be open-source (free!)

Page 8 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Support

¥ Well, you get complete source—that’s a start... ¥ Extensive on-line documentation (1200+ typeset pages) ¥ Commercial support—PerlSupport.com (http://www.perlsupport.com) and others ¥ Volunteers on the Internet—post questions to comp.lang.perl.misc ¥ Local “Perl Monger” User Groups (http://www.pm.org) ¥ Perl-5-Porters (P5P) provide bugtracking, and nearly immediate bugfixing (via the included perlbug bug reporting program)

Page 9 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Books

¥ , Second Edition (a Nutshell handbook from O’Reilly and Associates) by Larry Wall, Tom Christiansen, and Randal L. Schwartz, ISBN 1-56592-149-6 ¥ , Second Edition (another Nutshell book) by Randal L. Schwartz and Tom Christiansen (foreword by Larry Wall), ISBN 1-56592-284-0 ¥ Learning Perl on Win32 Systems (another Nutshell book) by Randal L. Schwartz, Tom Christiansen, and Erik Olson, ISBN 1-56592-324-3 ¥ Effective Perl Programming (from Addison-Weseley) by Joseph Hall with Randal L. Schwartz, ISBN 0-201-41975-0 (details on www.effectiveperl.com) ¥ The Perl Cookbook (Nutshell again) by Tom Christiansen and Nathan Torkington, ISBN 1-56592-243-3 ¥ Other books available: 100+ titles (new ones every month!)

Page 10 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Basic concepts

¥ Program is a text file, edited with ordinary text editor, made executable like a shell script ¥ Whitespace is generally insignificant (like a C program) ¥ Comments are pound-sign to end of line ¥ “main” program consists of all statements not within subroutines ¥ Syntax is C-like, with everything else thrown in (most statements are expression followed by semicolon) ¥ Variables spring into existence on assignment—no declaration required ¥ Entire source is compiled into internal representation, then interpreted from there (like Awk) ¥ Overriding design philosophy (from Larry): “Common things should be easy; advanced things should at least be possible”

Page 11 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Some brief explained examples

¥ Say “Hello, world!” #!/usr/bin/perl print "Hello, world!\n"; ¥ Get my home page use LWP::Simple; $content = get "http://www.stonehenge.com/merlyn/"; ¥ Mail me the results from a web form submission use CGI qw(:all); use Mail::Sendmail; my $name = param('name'); my $age = param('age'); sendmail(To => '[email protected]', Message => "name is $name and age is $age"); print header, start_html("Thanks"), h1("Thanks"), p("Thanks!"), end_html; ¥ Many actual production programs are indeed this short!

Page 12 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Perl as Glue

¥ Perl is friendly to other programs and connections ¥ Perl can launch child processes with full control (pipe, fork, waitpid, file-descriptor shuffling) ¥ Full TCP/IP sockets ¥ You can write a complete web server in Perl in a few lines of code ¥ Ditto web clients, mail clients, NNTP clients, Telnet clients, arbitrary socket interconnections ¥ Full System V IPC (shared memory, semaphores) ¥ Embed Perl in C or C++ ¥ Attach C or C++ to Perl ¥ Intertwine Perl and Java (JPL) (not for client-side apps)

Page 13 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Optimized for “90% text, 10% something else”

¥ Many problems involve shuffling text around ¥ Text comes from user input ¥ Text can also come from other programs ¥ Important to recognize patterns and extract useful information ¥ Perl’s text processing capabilities are excellent ¥ No “upper limit” on size of anything to declare or worry about (no “stack-smashing” security holes to worry about) ¥ But Perl also has the other stuff ¥ Like binary data, linkage to C, sockets, database connections ¥ These are often parts of the same problem, and Perl can do it ¥ Unlike most other languages, all the memory management (size and reuse) is automatic

Page 14 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Perl supports “programming in the large”

¥ Perl has a built-in warning system to note questionable code ¥ Separate modes for small vs. large programs (can require programmers to declare variables) ¥ Packages make possible sharing of top-level namespace (everyone can have their own private $idaho if they want) ¥ Full support for Object-Oriented Programming available, but optional (most small programs don’t use any OO at all) ¥ Extensive CPAN support gives most common tasks a rapid solution ¥ Interactive symbolic debugger built in ¥ Good runtime profiling and measuring tools available from CPAN ¥ GUI IDEs available from third-party commercial solutions

Page 15 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Good books and courses available

¥ Good quality documentation is available for free ¥ Documentation provided with Perl distribution ¥ Many more things available from the net (start at http://www.perl.com/) ¥ Or, nominal cost commercially produced books and magazines cover Perl as well ¥ Good Perl training is available worldwide from companies like Stonehenge (http://www.stonehenge.com/perltraining/)

Page 16 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Part Two: use Perl correctly

Page 17 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Y2K

¥ Perl itself has no problems with Y2K, but you can be silly with Perl’s functions ¥ Bad: two digit years ¥ Worse: just putting “19” in front of the value ¥ Contrary to popular rumor, localtime() and gmtime() are NOT Y2K-bad ¥ They return the year minus 1900, so add 1900 to get the right year number. $year = (localtime)[5]; print "19$year is WRONG\n"; print 1900+$year, " is GOOD!\n"; ¥ For an interesting detection solution, see http://www.cpan.org/authors/id/MJD/y2k.tgz use y2k; $year = (localtime)[5]; print "year is 19$year"; error—trapped at runtime print "year is ", 1900 + $year; permitted print "year is ", ($year % 100); also permitted

Page 18 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

The only Perl is “Perl version 5”

¥ Perl version 4 is not supported in any way, shape, or form ¥ Perl 5 (especially 5.004 and later) has numerous security fixes (many buffer overruns eliminated) ¥ Many modern libraries make programming simpler and safer ¥ “If you think you have found a bug in a version of Perl which is older than the Spice Girls, you should probably try upgrading to a newer version. :-)”—Tom Phoenix in comp.lang.perl.misc ¥ Code based on old Perl quirks is neither necessary nor reasonable

Page 19 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Use CGI.pm (not cgi-lib.pl)

¥ All CGI programs should use CGI.pm (or other modern modules), not the old decayed cgi-lib.pl, or hand-rolled modules: use CGI ":all"; bring in the CGI module, and define all normal subroutines ¥ For a transition from cgi-lib.pl, there’s “backward compatibility mode”: OLD: require "cgi-lib.pl"; &ReadParse; NEW: use CGI; CGI::ReadParse; ¥ See http://language.perl.com/info/www/!cgi-lib.html for motivation

Page 20 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Use CGI.pm’s function imports, not object interface

¥ CGI.pm is easier to use and read in non-OO (function call) mode instead of OO-mode ## object-oriented interface use CGI; my $query = CGI->new; this gets done once at the beginning of the file my $name = $query->param("name"); print $query->header, $query->start_html, ...; ## function-call interface use CGI ":all"; other variations possible my $name = param("name"); easy to read print header, start_html; ¥ One downside: namespace gets polluted, so be careful if retrofitting

Page 21 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Reduce duplicated code

¥ Create project-wide include files or modules for common tasks ¥ Simplest form is a simple require file ## in /some/dir/foo.pl package Foo; not necessary, but helps to partition global namespace sub bar { ... } 1; all require files must have a final true value ## in main program push @INC, "/some/dir"; require "foo.pl"; $result = &Foo::bar("para","meters"); ¥ Automatically gets pulled in only once even if included multiple times ¥ For more sophistication, use modules—see perldoc perlmod

Page 22 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Keep global variable usage to a minimum

¥ Use lexical (“my”) variables in subroutines sub my_routine { my ($first,$second) = @_; argument list my @third = (1..$first); temporary variable ... } ¥ Use lexical variables in “naked blocks” { my $line = ; $line is now a temporary, and will go away at block end ... } ¥ Variables so declared can be reused in many places in the program without collision ¥ Lexical variables are generally faster to access than global variables

Page 23 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Keep global variable usage to a minimum (cont’d)

¥ Use packages and package variables for shared data and subroutines package Fred; $b = 18; this is $Fred::b ¥ Lexical variables can be file-scoped as well ## in foo.pl my $temp; ... 1; ## in main program ... require "foo.pl"; The variable $temp is not visible to the main program ...

Page 24 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Warnings

¥ In general, enable warnings during development, but disable them in production #!/usr/local/bin/perl -w warnings enabled ¥ Warnings are meant as hints to developers—use them only if the developer can see them ¥ New versions of Perl often add warnings as new things are determined to be “bad style” ¥ These would rapidly fill up your error log ¥ Code to be deployed should however pass a compile-time-warnings check: perl -cw yourfile verify compilable code, with extra warnings enabled ¥ After installing a new Perl, you might try the -cw check on old code, but it’s not mandatory

Page 25 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Multiple writers must be coordinated

¥ Most reliable way is to use flock (works even on SysV because Perl emulates it with lockf) ¥ flock(HANDLE, 1) for all readers (shared lock—LOCK_SH) ¥ flock(HANDLE, 2) for all writers (exclusive lock—LOCK_EX) ¥ close HANDLE to release the lock ¥ Remember that things may have changed while you were waiting ¥ Best to follow all flock()s with a seek()—even if it’s just seek(HANDLE, 0, 1) ¥ If you’re writing to a growing log file, use seek(HANDLE, 0, 2) ¥ That forces the STDIO buffer to be refreshed from the disk if it happened to change ¥ flock(HANDLE, 8) is a danger flag—it’s almost nearly always wrong to unlock a handle before closing it (unlock, LOCK_UN)

Page 26 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Use Socket.pm, not sys/socket.ph

¥ In general, the .ph files are now frowned upon ¥ Luckily, nearly all of the constants wanted from the following: require "sys/socket.ph"; ¥ ... are now available by changing that line to: use Socket; ¥ However, if you’re starting from scratch, read on...

Page 27 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Use IO::Socket::INET, not roll-your-own socket stuff

¥ The IO::Socket::INET module provides TCP connections with much less hassle ¥ Old way: use Socket; $proto = getprotobyname('tcp'); get the protocol number for TCP socket(Socket_Handle, PF_INET, SOCK_STREAM, $proto); create this handle $port = getservbyname('smtp'); figure out what service number SMTP is (25!) $sin = sockaddr_in($port,inet_aton("127.0.0.1")); set the address (SMTP at localhost) connect(Socket_Handle,$sin); and finally connect ¥ New way: use IO::Socket::INET; my $Socket_Handle = IO::Socket::INET->new(PeerAddr => 'localhost:smtp'); ¥ And this object is even able to be passed around in variables! ¥ But if you’re just talking mail, read on...

Page 28 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Use LWP and Net::*, not roll-your-own standard protocol stuff

¥ There are libraries for all the standard protocols (SMTP, NNTP, HTTP, FTP, IRC, Telnet, etc.) ¥ Example: send a mail message: use Net::SMTP; my $mailer = Net::SMTP->new('localhost'); $mailer->mail('[email protected]'); sender goes here for (@people) { $mailer->recipient($_); } (many) recipients go here $mailer->data(); $mailer->datasend(<

I resign, effective immediately. END $mailer->dataend(); $mailer->quit(); ¥ Example: fetch a web page: use LWP::Simple; $contents = get "http://www.stonehenge.com/perltraining/";

Page 29 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Always check return values

¥ Ask yourself, “what if this call fails?” ¥ Not checking return values can lead to annoyingly long debugging sessions open THISFILE, "thatpath" or die "Cannot open thatpath: $!"; in program fred

Cannot open thatpath: File Not Found in fred - line 48 resulting error if open fails ¥ Include the filename and the $! variable in the error message as well ¥ Some calls are traditionally unchecked ¥ When’s the last time you tested the return value of print, for example? ¥ When in doubt, check it out ¥ For brevity, some other code in these materials occasionally omits return value checking

Page 30 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Don’t leave dead children lying about

¥ If you fork, you should wait (but not if Perl does the forking for you for something like system or ‘backticks‘) ¥ If you fail to wait, you start to accumulate zombies ¥ Zombies are already dead— “killing” them doesn’t do a thing (like a bad horror movie—“Night of the Living Procs”) ¥ Zombies are undesirable for long-running processes ¥ Most CGI scripts should not be long running, but if you have a longer-running process, you shouldn’t ignore the zombies ¥ Two common solutions to eliminating zombies ¥ The simplest is to ignore your dead children (this doesn’t work everywhere, however) $SIG{CHLD} = 'IGNORE';

Page 31 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Another anti-zombie solution—the “double fork”

¥ More portable, but slightly more expensive defined(my $kid = fork) or die "cannot fork: $!"; if ($kid) { waitpid($kid,0); main process (parent) waits } else { defined(my $grandkid = fork) or die "kid cannot fork: $!"; if ($grandkid) { exit 0; kid exits quickly after forking } else { ## grandkid code is here grandkid does the real work } } ¥ Grandkid becomes “child of init” (parent process ID is 1) ¥ Use this when the exit status of the work is not important (you can’t see it anyway)

Page 32 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Document your code

¥ First and foremost: good comments ¥ Perl supports embedded documentation, called POD (Perl On-line Documentation) ¥ Embedded POD can be translated to manpages, HTML, and many other formats ¥ POD is understood by the Perl compiler, and is skipped over nicely ¥ See perldoc perlpod for details

Page 33 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Use debugging code, controlled by a global variable

¥ If you want temporary behavior for debugging code, use a global constant use constant DEBUGGING => 1; ... if (DEBUGGING) { print "This is $This\n"; } ¥ By using the constant pragma, the code can be optimized away quickly (compiled, but not saved for execution) ¥ If you have special debugging features enabled that give you extra powers, be sure those are turned off before releasing the code to production!

Page 34 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

See perlstyle for additional ideas

¥ Why worry about style? ¥ Because errors are harder to spot in ill-formatted or inconsistently formatted programs ¥ Available through man perlstyle if your MANPATH is correct ¥ Or perldoc perlstyle should work in any case

Page 35 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Taint checks

¥ Automatically enabled when running setuid or setgid ¥ Can be manually enabled from command-line with -T #!/usr/local/bin/perl -T ¥ Note: to check this for -cw, you must use -cwT ¥ Recommended for all CGI programs (which are effectively setuid, but not really setuid) ¥ Basic rule: Nothing from outside the program can trivially affect anything else outside the program!

Page 36 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Inputs that are tainted

¥ Data from filehandles (including STDIN) ¥ This especially includes any CGI data read in from a POST-form ¥ Filehandles can be “trusted” using IO::Handle’s untaint method: use IO::Handle; do this once at the beginning of the program STDIN->untaint; works in 5.004 or later my $input = ; now trusted ¥ Use this sparingly though! ¥ Command line args (@ARGV) ¥ The environment variables (%ENV) ¥ This includes PATH by default, so no child process launches are permitted until you clean PATH: $ENV{PATH} = "/bin:/usr/bin:/usr/ucb"; now we can launch children ¥ This also includes any CGI data like params of a GET-form

Page 37 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Tainting is sticky

¥ Nearly all operations that use tainted data in any way also result in tainted data chomp($data = ); $data is tainted $first_char = substr($data, 0, 1); so $first_char is tainted $x = "foo" . substr($data, 0, 0); and $x is tainted even though $data isn’t there! ¥ The only way to get data from tainted side to untainted side is via the regex match vars $data =~ /^(\w+)$/ or die "naughty data"; we expected a single word $safe_data = $1; $safe_data is now a clean version of $data ¥ Be very careful what you permit into the @bad_example = map { /(.*)/s; $1; } @tainted; this untaints everything, but is BAAAAD ¥ Doing so completely eliminates all the safety you get from tainting!

Page 38 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Actions that are dangerous

¥ Anything that affects outside world ¥ Launching a child process (via system, ‘backticks‘, open process, or exec) requires both a clean argument and a clean PATH chomp ($hostname = ‘hostname‘); illegal until we set PATH $ENV{PATH} = "/bin:/usr/bin:/usr/ucb"); chomp ($hostname = ‘hostname‘); now OK $result = ‘grep $tainted_data file1 file2 file3‘; definitely bad idea if ($tainted_data =~ /(\w+)/) { $result = ‘grep $1 file1 file2 file3‘; safer, but be very careful of proper regex } ¥ Exceptions: system or exec with multiple args aren’t affected by unclean args ¥ Even safer would be to avoid a shell entirely (see code later)

Page 39 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Other dangerous actions

¥ Opening a file with tainted data for names if the file ends up not being opened for reading (evil person could sneak | in there!) ¥ Using tainted data in a system-type call unlink $this, $that; illegal if $this or $that is tainted kill 15, $bad; illegal if tainted if (‘ps x‘ =~ /^\s*(\d+).*\s+httpd\s+/) { kill 15, $1; but this is legal because it’s $1 } rename param("source"), "/htdocs/".param("dest"); definitely illegal ¥ Globbing is always illegal, even if you set PATH (lame csh has a seriously bad security hole) ¥ Perl versions before 5.004 didn’t catch this—upgrade now!

Page 40 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

No need for shells to launch children

¥ Launching a child process via single-arg system, ‘backticks‘, open process, or exec can invoke a shell if the arg is complex enough ¥ It’s OK if there aren’t any shell metachars involved (stick with \w and spaces or tabs): $search_for = "Monica"; @found = ‘grep $search_for brief1 brief2 brief3‘; ¥ But this can get dangerous if untested $search_for = "foo|bar"; Ouch! ¥ Think this can’t happen? Watch this: $search_for = param("look_for"); now we trust the user... bad! ¥ But we can always avoid the shell, which makes it safe

Page 41 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Coding to avoid the shell

¥ Here’s code modified slightly from perlsec(1): die unless defined $pid = open(KID, "-|"); if ($pid) { parent here @result = ; close KID; } else { child here $ENV{PATH} = "/bin:/usr/bin"; open STDIN, "

Page 42 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Coding to avoid forking

¥ Often no need to fire off separate programs ¥ Doing it within Perl is faster and more secure ¥ No need to call grep for simple searches open FOO, "thatfile"; @found = grep /\blove\b/, ; close FOO; ¥ No need to call hostname to get the hostname use Sys::Hostname; $me = hostname; or just use $ENV{SERVER_NAME} in CGI ¥ And you can eliminate date from that list too $now = localtime; $london_now = gmtime; ¥ Sending mail? Talk to the daemon, not a program! See the Net::SMTP example earlier

Page 43 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

CGI Security—Hidden fields

¥ Hidden fields are perhaps misnamed ¥ They aren’t hidden—they’re clearly visible in the HTML source ¥ They can also show up in the server logs on an ACTION=GET form submission ¥ Don’t presume the user won’t look at them ¥ Also don’t presume that they are immune to tampering ¥ A user could save the HTML page, edit the hidden form data with a text editor, and wreak havoc

Page 44 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Don't put sensitive data in the GET URL

¥ The URL is visible in the location field of the browser ¥ The URL typically ends up in the history of the browser as well ¥ And the web logs ¥ And watch out for bookmarked URLs

Page 45 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Don’t count on REFERER1

¥ The REFERER header (available as $ENV{HTTP_REFERER} in Perl) purports to be the URL of the page visited before the current URL was fetched ¥ Often this is used as a check to make sure that the proper page was used to trigger a particular CGI action ¥ But, it’s an unverified header! ¥ Security through REFERER is no security at all ¥ REFERER can be trivially forged ¥ Worse: it won’t work through firewall proxies, so legitimate users will be left in the cold

1. It’s not even spelled right!

Page 46 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Don't presume anything about the execution environment

¥ Set up your own PATH ¥ Watch your current directory! ¥ Remember that you are most likely running as the webserver user, not your own user-ID ¥ Also check out everything in http://www.cpan.org/doc/FAQs/cgi/idiots-guide.html, “The Idiot's Guide to Solving Perl CGI Problems” ¥ Don’t be offended by the name!

Page 47 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

The HTTP “Username”

¥ Extracted from that little username/password pop-up box ¥ Valid only when the webserver is doing “basic authentication” in a particular area (often via the right .htaccess file) ¥ Comes into the script via the REMOTE_USER environment variable ¥ Hard to fake, but it’s sent in clear-text across the wire ¥ Therefore, easy to snoop, so don’t put too much credence in it ¥ Better: use SSL (https://...) for that really private stuff ¥ Also, browsers remember that stuff sometimes, so it might be someone else borrowing a browser ¥ Hard to clear out (you must get the webserver to send the right error, and then the user has to not enter it when prompted)

Page 48 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Don’t use /bin/mail or /bin/mailx to send mail

¥ Use sendmail or SMTP to send mail ¥ For sendmail, put the addresses in the headers, not the command line my $destination = '[email protected]'; open SENDMAIL, "|/usr/lib/sendmail -oi -odq -t" or die "Cannot fork: $!"; print SENDMAIL <

$query_results EOF close SENDMAIL; die "sendmail failed: $?" if $? and ($? >> 8) != 75; ¥ Simpler and safer to use Net::SMTP (see earlier) ¥ /bin/mailx allows tilde escapes at the beginning of the line—this cannot be disabled

Page 49 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Use a valid return address when sending mail

¥ That way, if the mail bounces, it bounces to someone useful ¥ More for debugging and tracing than for security ¥ Point the return address at someone that can debug a potential problem ¥ Don’t point it at an autoresponder (mail loop!) ¥ With SMTP, the return address can be arbitrary ¥ With sendmail, the header-from is arbitrary, but the envelope-from (and header-sender) will be the web server user-id ¥ Often, bounce messages are sent to the envelope-from ¥ But vacation replies will often go to the header-from!

Page 50 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Writing to STDERR

¥ Most web servers store standard error stuff in the logs ¥ Being verbose there is not being kind to the webmaster ¥ Instead, create your own logfile, and open STDERR to it open STDERR, ">>/some/standard/place/yourtool"; note: return value not checked warn "danger, will robinson!"; writes to the selected logfile instead of the web log ¥ Be sure to redirect STDERR on error-chatty programs (like PGP) open PROGGY, "|/usr/bin/random/prog 2>/dev/null"; toss it away $result = ‘rm -rf /some/place 2>&1‘; merge with standard out

Page 51 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Failures should never reveal internal information

¥ An exception should not dump out interesting internal bits to the browser! ¥ Especially vulnerable: pathname to program, implementation language, key parameters, database user-ID, debug settings ¥ Install exception handlers that return minimal info, and log the rest BEGIN { open STDERR, ">>/some/standard/place/your_tool"; $SIG{__DIE__} = sub { print STDERR map { localtime() . ":$0:$_\n" } "caught exception:", $_[0]=~ /(.*)\n?/g; exit 1; trigger error 500 } } ¥ Consider the use of CGI::Carp (not installed by default, but available in the CPAN)

Page 52 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Throw away bad books

¥ There are some scary books out there ¥ Be sure to check the reviews by experts ¥ Some books have typos ¥ Some typos are so bad the programs provided won’t even compile! ¥ Others actually lead reader astray ¥ One somewhat popular book was even written by an author who said he hated Perl

Page 53 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Get good support for advanced technology

¥ Effective Perl Programming and the Perl Cookbook both have good “best practices” information ¥ As before, get good on-site and open-enrollment training from worldwide leaders, like Stonehenge ¥ Stonehenge provides short courses, long courses, custom courses, in both on-site and open-enrollment formats ¥ Beware, some training companies are just “slide readers”

Page 54 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Conclusion

Page 55 of 56 STONEHENGE CONSULTING SERVICES 4470 SW Hall Suite 107 Beaverton, OR 97005 (503) 777-0095

TM

Questions and answers

¥ You can write to Randal Schwartz at [email protected], or call (503)777-0095 ¥ Or on the web— http://www.stonehenge.com/merlyn/WebTechniques/ Randal’s WebTechniques columns http://www.stonehenge.com/merlyn/UnixReview/ Randal’s tutorial columns http://www.pm.org/ worldwide Users Groups http://www.perl.com/ O’Reilly’s Perl Home Page http://www.stonehenge.com/perltraining/ to get more courses like this one! http://www.perlsupport.com/ for commercial technical support http://www.go2net.com/people/paulp/cgi-security/safe-cgi.txt CGI security FAQ http://www.cpan.org/doc/FAQs/cgi/idiots-guide.htm Idiot’s Guide for CGI

Page 56 of 56