TweetFollow Us on Twitter

Enabling CGI Scripts, The Second

Volume Number: 19 (2003)
Issue Number: 10
Column Tag: Programming

Untangling the Web

Enabling CGI Scripts, The Second

by Kevin Hemenway

You've enabled CGI, but how do you know it's good?

In the last issue, we learned about CGI scripts: what they are, what they can do, how they're already enabled within Apache, and how to tweak that configuration to be more URL friendly. What we didn't do is teach you anything for the future: at most, we brought a wide-eyed wonder-boy to a patch of poison ivy, and backed away slowly. Will he rub it on his skinned knee? Pin it to little Susie's dress as a token of his affection? Roll around in it like catnip? Where is the inbred fear necessary for every child's survival?

Insert transitional one-liner here!

Dissection--Similarities

Before we can understand, be aware, and watch for the security ramifications of running CGI scripts from unknown and untrusted third parties, we need to see how they're coded, how poorly written ones can ruin our mornings, and how to look for some semblance of quality. The quickest way to get a general feel is with the two sample scripts already installed with Apache: /Library/WebServer/CGI-Executables/printenv and /Library/WebServer/CGI-Executables/printenv/test-cgi. If you looked at their source code last month, you may have noticed they're written in two different languages.

The smaller of the two scripts, test-cgi, starts with #!/bin/sh, whereas printenv instead uses #!/usr/bin/perl -T. These lines, specifically the #! prefix, are often called the "shebang", and tell us which interpreter will execute the programming instructions that follow. The interpreter located at /bin/sh, rarely seen in production CGI, indicates that the rest of the code is written in the shell scripting language. Any CGI script you deploy will need to have some sort of shebang--whether it's /bin/sh, /usr/bin/perl, /usr/bin/python or something else entirely, it's absolutely required. Not only is it necessary, it also has to be accurate: if your only Perl is /sw/bin/perl, then the shebang should point there instead. Shebangs can also contain command line arguments: in printenv, -T is passed directly to the /usr/bin/perl interpreter (where it means something we'll cover a bit later).

Another similar difference between our two scripts is the printing of something called a Content-type (Listing 1), which tell the requesting user-agent (your visitor's browser) what sort of data it's about to receive (an image to render, text to display, XML to parse, etc.). The Content-type will never actually be shown in your final output--it's hidden pixie dust for the browser's benefit only (if you're curious, Mozilla allows you to view the Content-type by getting the "Page Info" of the current URL). Without this crucial bit of contextual magic (and the two required newlines), Apache will fail your CGI scripts with an "Internal Server Error". This error is never a satisfying explanation--you'll need to check Apache's /var/log/httpd/error_log for the exact reasoning.

Listing 1: Printing the Content-type in Shell and Perl

From the sample CGI scripts printenv and test-cgi

# content type display from test-cgi
# note that echo spits out a newline,
# 2 echo's for the 2 required newlines.
echo Content-type: text/plain
echo
# and the similar entry from printenv
print "Content-type: text/html\n\n";

The values of our Content-types (text/plain and text/html) didn't just appear out of thin air--they're MIME types, and most any file you've ever worked with has one. You can find a large listing of MIME types, based on their common file extensions, by perusing the /etc/httpd/mime.types file. For example, the matching MIME types for JPEG, XHTML, Quicktime, and Microsoft Word files are:

image/jpeg                      jpeg jpg jpe
application/xhtml+xml           xhtml xht
video/quicktime                 qt mov
application/msword              doc

If you can't find the matching MIME type for the data you're interested in serving (either because it's not in the mime.types file or Google has spurned your search request), you can use the "some sort of data" MIME type of application/octet-stream. This has already been explicitly assigned to a number of files, including Apple disk images:

application/octet-stream   dms lha lzh exe class so dll dmg

Dissection--Why The Perl Script Is Arguably Stronger

All CGI scripts, regardless of what they're programmed in, can be run from the command line--whether they actually do anything useful is a case-by-case basis. This is a surprisingly useful bit of information: since troubleshooting and debugging happens best when unfrilled by complication, removing Apache from the process can prove helpful. Running your CGI scripts on the command line can preemptively weed out problems like missing Content-type's, file permission errors, invalid syntax problems, missing language extensions, and so forth.

Both the test-cgi and printenv scripts run "successfully" at the command line, although only the first gives any useful output (Figure 1). Compare this to the regular browser-based output we demonstrated in the last MacTech (or simply re-access http://127.0.0.1/cgi-bin/test-cgi). The first line is that dastardly Content-type and, as mentioned before, is normally processed by the browser and removed from the final display. Since we're running the script without the benefit of a web server or browser, the Content-type is viewable without extra effort. This becomes a handy barometer: if you run your CGI script from the command line and there's no Content-type, it'll never run correctly under Apache.


Figure 1: The slightly undefined test-cgi, when run in the Terminal

But wait... there's no Content-type if we try to run printenv (in fact, there's nothing at all), so why does it work when we access it by URL (http://127.0.0.1/cgi-bin/printenv)? In actuality, this is one of the "strengths" of the Perl version. If you check the source code, the next line after our required shebang (ignoring comments) is:

exit unless ($ENV{'REQUEST_METHOD'} eq "GET");

This terminates the script unless it was invoked via a GET request. Generically speaking, unless it is a POST, every request a web browser makes is a GET with or without key/value pairs. Since the shell isn't a web browser, no GET is issued and the script terminates. If we wanted to get fancy, we could fake the required method by running setenv REQUEST_METHOD GET && ./printenv (if you're using the tsch shell; REQUEST_METHOD=GET ./printenv if you prefer bash). As a result, we get a Terminal full of HTML listing the environment variables. We can redirect this mass of HTML to a file by adding > output.html to our previous command line; Figure 2 shows the generated file.


Figure 2: Shell output of our tricked printenv script

Figure 2 also gives us another reason why the Perl script is stronger: it doesn't pretend to know what the environment is going to look like. test-cgi, hard-coded to display the values of known variables (SERVER_SOFTWARE, SERVER_NAME, GATEWAY_INTERFACE, etc.), shows nothing but undefined values when run from the Terminal (Figure 1), where those specific entries don't normally exist.

Three Ways Perl CGI Scripts Can Be Improved

The bulk of the code within the printenv script caters to creating a pretty HTML page, something not important to the true purpose of generating a list of the current environment. To make our upcoming improvements more clearly, we'll base our changes on the Perl script shown in Listing 2, which does the exact same thing as printenv, only without the HTML. For all intents and purposes, this is a working CGI script: it's got the shebang pointing to the correct Perl interpreter, and it prints a plain-text Content-type before any other data.

Note that even though we're talking specifically about CGI scripts, the following improvements can, and should, be made in most any Perl script, especially those to be used in production environments. Security should never be a feature.

Listing 2: Printing the environment more simply

Our base.pl script could use some improvements.

#!/usr/bin/perl
print "Content-type: text/plain\n\n";
foreach $var (keys %ENV) {
   print "$var = $ENV{$var}\n";
}

Save this file as base.pl and run it from the command line; my output is in Figure 3. None of our upcoming improvements will change this display and, as you can see by comparing it to Figure 2, it's identical save for the loss of HTML (and the differences between Safari and the Terminal's interpretation of TERMCAP).


Figure 3: Our rewritten script's (base.pl) output

Our improvements to the script are quite minimal additions, but they ensure that user data has been properly checked for dangerous input, warnings have been enabled for common mistakes or typos that don't necessarily stop a script from running, and a stricter development environment has been used to encourage stronger coding and careful variable declaration. The revised script is shown in Listing 3.

Listing 3: Printing the environment more strongly

Our revised script is three times stronger than before.

#!/usr/bin/perl -wT
use strict;
print "Content-type: text/plain\n\n";
foreach my $var (keys %ENV) {
   print "$var = $ENV{$var}\n";
}
  • Use warnings: The first change, adding -w to the shebang, turns on Perl's warnings pragma, which spits a list of optional, non-fatal warnings to STDERR (which becomes Apache's error_log when run as a CGI). Technically, you don't have to address any of the messages since the script will continue on regardless, but they'll alert you to typos, uninitialized values, deprecated functions, and a slew of other mishaps that can eventually escalate into full-blown bugs. Typically, the messages are terse enough to be useful for seasoned Perl programmers, but you can increase their verbosity by adding use diagnostics; within the body of your code.

  • Use strict: Our third and fourth changes complement our warnings. Perl's strict pragma should be used in any script that is more than "casual", and ensures that every variable is pre-declared and localized, and that other "unsafe constructs" are detected and addressed. Unlike warnings, any error that triggers strict will stop your script from continuing further. You'll notice that we've localized our $var variable with the my() function. The first time you use strict, it'll feel like an unwieldy and overly doting mother, but scripts that compile cleanly benefit from an attention to detail that strengthens their quality immensely.

  • Use taint: Even though it is "strongly recommended", very few Perl or CGI scripts use taint mode, which is what the -T on the shebang enables. Under this mode, any outside data received by your code is considered highly dangerous, and will cause script errors until it has been checked for safety. These safety checks can be as simple as ensuring that a command line argument only contains alphanumerics, or that the process you're spawning isn't being handed potentially damaging shell metacharacters. While taint mode will force you to focus more strongly about the evils of the outside world and exactly what data you expect, programmers who misunderstand how to "untaint" data may inadvertently do so incorrectly, creating a false sense of security.

These programming additions aren't the ultimately panacea, but merely a placebo. Yes, your code will be stronger with them, but that doesn't mean crucial bugs won't creep in and ruin your day. Serious coders and sysadmins should take a look at the following sampling of Perl and CGI security links:

  • The Perl Security manpage, accessible by typing man perlsec in your Terminal, can also be read online at http://www.perldoc.com/perl5.6.1/pod/perlsec.html

  • "Avoiding security holes when developing an application", a six part series from LinuxFocus.org: http://www.linuxfocus.org/English/November2001/article203.shtml

  • SecureProgramming (http://www.secureprogramming.com/) offers a huge collection of links to over 50 articles, books, recipes to learn from and adapt, and more.

  • RFP's "Perl CGI problems", which appeared in an old issue of the seminal Phrack magazine, still remains relevant: http://www.wiretrip.net/rfp/txt/phrack55.txt

  • CERT's "How To Remove Meta-characters From User-Supplied Data In CGI Scripts", in both Perl and C: http://www.cert.org/tech_tips/cgi_metacharacters.html. Handy for when you're looking to untaint some data.

  • The "Securing Programming for Linux and Unix HOWTO", available from http://en.tldp.org/HOWTO/Secure-Programs-HOWTO/. Similar articles like "The Hack FAQ" (http://www.nmrc.org/pub/faq/hackfaq/index.html), and the "WWW Security FAQ" (http://www.w3.org/Security/Faq/www-security-faq.html) will also prove insightful.

    Choosing a CGI Script for Deployment

    The above programming suggestions are fine if you're solely looking at the code quality of a potential CGI script, but there are few more areas to investigate before you can consider a program worthy of being installed on your server:

    • Check the Bugtraq archives (http://securityfocus.com/archive/1). Anyone interested in security should be reading Bugtraq, where a large community of hackers, white hats, sysadmins, and professionals regularly post bugs, exploits, and warnings for insecure products. Occasionally, you'll also see new whitepapers concerning various aspects of security and programming. Before installing new scripts, comb the archives to see if any advisories have been posted. If so, ensure they've been fixed before using the code.

    • Googling for problems can prove illuminating, as you'll often find common tech support problems, heaps of praise or scorn for the code or author, and occasionally, other web hosts who offer the script for their own customer base.

    • Check the dates: When was the script last updated? Is it so long ago that no one will give a darn if you have a problem? Just because a script doesn't have any reported problems in Bugtraq doesn't mean that it isn't susceptible to relatively new exploits like cross-site scripting attacks (http://www.cgisecurity.com/articles/xss-faq.shtml). Code that has been updated recently has a better chance of good turnaround time for crucial fixes, updates, and support.

    • Got logfiles? Most CGI scripts don't have any logging capability, primarily because they only do one small thing (like email forms, add one to a number, display a calendar, etc.) Some complicated scripts, however, can benefit from logging, especially those with built-in user authentication ("who is using my site?") or flaw tracking ("a bug occurred at [time], and things turned awry [like this]"). Scripts can use their own logfiles or Perl's Sys::Syslog module to log directly to /var/log/system.log.

      Homework Malignments

      In our next column, we'll move on to configuring PHP, as well as explain the up- and downsides between forking processes (like CGI) and embedded modules (like mod_php). We'll explore the default configuration of PHP, the non-existent configuration file (php.ini) and, if we have time, how to install MySQL and do a few integration tests. For now, students may contact the teacher at morbus@disobey.com.

    • Besides -w, you can also enable Perl's warning pragma with use warnings; (similar to use strict;). Subtle differences exist between the two--research them and find out which satisfies your programming needs better.

    • Any Perl script with logging may eventually run up against a perceived "buffering" problem, the sordid details of which are explained in Mark Jason Dominus' "Suffering from Buffering?" (http://perl.plover.com/FAQs/Buffering.html).

    • If you're looking to brush up on your Perl knowledge, you can't go wrong with O'Reilly's Learning Perl, The Perl Cookbook (which just received an impressive Second Edition update), and the recent Learning Perl Objects, References, & Modules. You can read sample chapters from all the books at http://www.oreilly.com/.


      Kevin Hemenway, coauthor of Mac OS X Hacks and Spidering Hacks, is better known as Morbus Iff, the creator of disobey.com, which bills itself as "content for the discontented." Publisher and developer of more home cooking than you could ever imagine (like the popular open-sourced aggregator AmphetaDesk, the best-kept gaming secret Gamegrene.com, the ever ignorable Nonsense Network), he's twirling his hair and trying not to cheerlead. Contact him at morbus@disobey.com.

  •  

    Community Search:
    MacTech Search:

    Software Updates via MacUpdate

    How to win big in Slots Deluxe
    Cheating while gambling is illegal and morally wrong, and in some parts of the world it leads to men with names like Vinnie "Six Knuckles" Manchenzo beating you to a pulp in a dark alley. [Read more] | Read more »
    How to take over the world in Dictator 2
    Running a country isn't easy - especially when you're a dictator who wants to take over the world and crush everyone in your path while you do it. [Read more] | Read more »
    Tips and tricks to get a higher score in...
    Tank.iois - you guessed it! - another multiplayer arena battler likeAgar.io and Slither.io. It does differentiate itself by putting you in a tiny tank though, so it's not exactly the same. To help you get that all-important high score, we've got a... | Read more »
    How to unlock characters in One Tap Tenn...
    As the title suggests, One Tap Tennis requires only a single tap to play its particular brand of tennis, and rewards you with a ton of unlockable characters if you perform well. Fortunately for you, we at 148Apps have got a few tips and tricks to... | Read more »
    Grab it now: Game Craft’s Legend of War...
    The real time strategy game is now available for you to sink your teeth into, through the App Store and Google Play. Combining elements of skill, strategy and empire building, Legend of War is a real gamers’ game. [Read more] | Read more »
    Skateboard Party 3 ft. Greg Lutzka (Gam...
    Skateboard Party 3 ft. Greg Lutzka 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: Skateboard Party is back! This third edition of the popular sports franchise features professional skater... | Read more »
    Cubious (Games)
    Cubious 1.0 Device: iOS Universal Category: Games Price: $.99, Version: 1.0 (iTunes) Description: Cubious – How smart are you? How high is your IQube? Solve the impossible puzzles to find out, and help a lost little cube find his... | Read more »
    Goat Simulator Waste of Space (Games)
    Goat Simulator Waste of Space 1.1 Device: iOS Universal Category: Games Price: $4.99, Version: 1.1 (iTunes) Description: ** IMPORTANT - SUPPORTED DEVICESiPhone 4S, iPad 2, iPod Touch 5 or better.** | Read more »
    Wildfulness - Unwind in nature and calm...
    Wildfulness - Unwind in nature and calm your mind with nature sounds and illustrations 1.0 Device: iOS Universal Category: Healthcare & Fitness Price: $1.99, Version: 1.0 (iTunes) Description: Spending time in nature helps you to... | Read more »
    Dr. Panda Racers (Education)
    Dr. Panda Racers 1.0 Device: iOS Universal Category: Education Price: $2.99, Version: 1.0 (iTunes) Description: STEP ON THE GAS, RACE AND WIN!Fasten your seat belts and get ready to race! Speed your way to the finish line while doing... | Read more »

    Price Scanner via MacPrices.net

    Enterprise Workers Pick Technology Over Perks...
    New Adobe study shows surprising attitudes about office jobs and where the future of work is heading. Adobe has released survey findings revealing that a surprising 70 percent of U.S. office workers... Read more
    Goal Zero and OtterBox Partner to Expand iPh...
    Goal Zero, specialists in portable power, have announced a partnership with OtterBox, brand smartphone case protection, to offer the Slide and Slide Plus Batteries as modules compatible with the new... Read more
    15-inch Retina MacBook Pros on sale for up to...
    B&H Photo has 15″ Retina MacBook Pros on sale for up to $210 off MSRP. Shipping is free, and B&H charges NY tax only: - 15″ 2.2GHz Retina MacBook Pro: $1799 $200 off MSRP - 15″ 2.5GHz Retina... Read more
    Clearance 2015 13-inch MacBook Airs available...
    B&H Photo has clearance 2015 13″ MacBook Airs available for $250 off original MSRP. Shipping is free, and B&H charges NY sales tax only: - 13″ 1.6GHz/4GB/128GB MacBook Air (MJVE2LL/A): $799... Read more
    Apple refurbished Apple TVs available for up...
    Apple has Certified Refurbished 32GB and 64GB Apple TVs available for up to $30 off the cost of new models. Apple’s standard one-year warranty is included with each model, and shipping is free: -... Read more
    21-inch iMacs on sale for up to $120 off MSRP
    B&H Photo has 21″ iMacs on sale for up to $120 off MSRP including free shipping plus NY sales tax only: - 21″ 3.1GHz iMac 4K: $1379.99 $120 off MSRP - 21″ 2.8GHz iMac: $1189 $110 off MSRP - 21″ 1... Read more
    Kanex Introduces GoPower USB-C Rechargeable B...
    Kanex has announced its GoPower USB-C portable battery for the USB-C MacBook, featuring the new industry standard connector and cable used for connectivity and power. Providing users with a new... Read more
    Convertible and Detachable Devices Winning Ov...
    According to the latest figures published by International Data Corporation (IDC), Western European shipments of ultraslim convertibles and detachables posted positive growth (44.7%) to account for... Read more
    New MacBook Pros And Will MacBook Air Be Upgr...
    With my mid-2013 13-inch MacBook Air closing on its third anniversary come November, I’m in system upgrade mode. Actually the Haswell CPU equipped Air is still doing a fine job, but my good wife is... Read more
    Apple’s Education discount saves up to $300 o...
    Purchase a new Mac or iPad using Apple’s Education Store and take up to $300 off MSRP. All teachers, students, and staff of any educational institution qualify for the discount. Shipping is free, and... Read more

    Jobs Board

    *Apple* Project Engineer - Smart Source Inc...
    SmartSource is in need of an Apple Project Engineer for a 12 month contract opportunity in Pittsburg, PA. Role: Apple Project Engineer Location: Pittsburg, PA Read more
    Automotive Sales Consultant - Apple Ford Linc...
    …you. The best candidates are smart, technologically savvy and are customer focused. Apple Ford Lincoln Apple Valley is different, because: $30,000 annual salary Read more
    Service Assistant - *Apple* Chevrolet *App...
    Apple Automotive is one of the fastest growing dealer...and it shows. Consider making the switch to the Apple Automotive Group today! At Apple Automotive, we Read more
    Editor, *Apple* News - APPLE (United States...
    Job Summary The Apple News team is looking for a passionate and knowledgeable editor with experience covering entertainment/pop culture and experience running social Read more
    *Apple* Nissan Service Technicians - Apple A...
    Apple Automotive is one of the fastest growing dealer...and it shows. Consider making the switch to the Apple Automotive Group today! At Apple Automotive , Read more
    All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.