CGI Scripting and Perl
In this activity, we’ll be experimenting with the cgi-bin and writing web scripts in BASH and Perl.
Environment Variables
Apache provides a large number of variables about the request and server into a CGI script using environment variables. The HTTP Request’s GET variables are also provided in the environment. Each language we consider will have a slightly different method for accessing them:
- C:
getenv("VARIABLE_NAME")
returns the variable’s value as a string - BASH: variables are accessible using
$
as$VARIABLE_NAME
- Perl: variables are set in the
%ENV
hash and can be accessed as$ENV{VARIABLE_NAME}
Review the
example.pl
Perl script andexample.sh
BASH script in your Docker container’s cgi-bin.Open up each file through Apache, by navigating to them:
http://localhost:8080/cgi-bin/example.pl and
http://localhost:8080/cgi-bin/example.shNotice what variables are provided to the script.
Question: Should we present all of these variables to the output on a production system?
Question: How can these variables help us to tailor our responses to a particular user?
Writing Perl
Now let’s experiment with writing some Perl.
Creating a Form
We will first create an HTML page that prompts the user for some information. You are welcome to use the HTML below or create your own.
<!DOCTYPE html>
<html lang="en" data-bs-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="author" content="your name">
<meta name="description" content="include some description about your page">
<title>Perl Activity</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
</head>
<body>
<main class="container">
<h1>Perl Activity</h1>
<form method="GET" action="/cgi-bin/perlactivity.pl">
<div class="mb-3">
<label for="firstname" class="form-label">First Name</label>
<input type="text" class="form-control" id="firstname" name="firstname">
</div>
<div class="mb-3">
<label for="lastname" class="form-label">Last Name</label>
<input type="text" class="form-control" id="lastname" name="lastname">
</div>
<div class="mb-3">
<label for="food" class="form-label">Favorite Food</label>
<input type="text" class="form-control" id="food" name="food">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"></script>
</body>
</html>
Save the above HTML into a file, perlactivity.html
in your www
directory. We will use this file to send data to our Perl script in cgi-bin.
Note that we are not saving the html file above directly in the cgi-bin with our Perl scripts.
Try saving the html file into the
cgi-bin
directory and accessing it through Apache.Question: Does Apache serve the file as expected? What happens?
Review the Apache log file in your Docker container. What does Apache report.
This file provides form input for the user to enter their first and last name as well as their favorite food. When the user submits the form, it sends an HTTP GET request to a Perl script in our cgi-bin.
Question: in this GET request, how are the data passed to the backend? Is this a security vulnerability?
We will need to update our Docker container before continuing! While we have Perl installed, we need the CGI module to help us process user input through HTTP. You can do this in one of two ways.
- If you are using Docker Desktop, open the Dev Environments tab, then click on the web container listed under the course’s environment. The Logs tab should be open and you will see the Apache logs. Open the Exec tab, which will display a prompt as follows:
#
There, enter
apt install libcgi-pm-perl
and press enter. It will then prompt you to install some perl packages. Continue withy
. Once this completes, you are ready to continue.
- If you are using Docker on the command line, open a new terminal window and connect to the Docker instance as:
docker exec -it web bash
Then, enter the install command above,
apt install libcgi-pm-perl
and install the packages.
Perl Script
Save the following code as a new file perlactivity.pl
inside your cgi-bin
directory. This file will respond to the user’s form submission. We will add additional logic as we go.
#!/usr/bin/env perl
# Use the CGI module
use CGI;
# Create a new CGI object
my $q = CGI->new;
# Access the firstname GET parameter
my $first_name = $q->param('firstname');
# Print a hello!
print "Hello $first_name!\n";
Next, we are ready to test our Perl script. It should print out the firstname
GET parameter provided by an HTTP request. Open your perlactivity.html
through Apache, fill out the form, and submit.
It looks like we have another Internal Server Error. Review the Apache log in Docker to determine the cause.
The Apache logs in Docker will be very helpful moving forward. By default, any server-side errors will be printed in the error log file displayed here. On a production system, these logs are typically stored in
/var/log/apache2/error.log
.Likewise, Docker is also showing access logs in the same stream. Access logs have the following format:
172.18.0.1 - - [21/Feb/2024:15:01:27 -0500] "GET /activities/perlactivity.html HTTP/1.1" 200 827 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:122.0) Gecko/20100101 Firefox/122.0"
Access logs are helpful for understanding traffic to our site and any potential attacks. Some attacks target systems looking for vulnerable web applications; if our system does not have that code, Apache will return a 404. On a production system, access logs are typically stored in
/var/log/apache2/access.log
.
Our error indicates that the server does not have access to execute our Perl script. For any script in the cgi-bin
directory, Apache must have execute permissions so that it can fork and exec the script. Additionally, our Docker container follows Linux file permissions, so we will need to allow the Apache user to execute the script.
Re-open the web Docker container’s terminal. Our cgi-bin
directory is mapped to /usr/lib/cgi-bin
in Docker. Change directory to the cgi-bin and allow users to execute our new Perl script:
cd /usr/lib/cgi-bin
chmod a+x perlactivity.pl
Now that Apache can execute our Perl script, return to the browser and reload the page. Note what happens next! Review the example.pl
file to fix your Perl script. Once you have fixed all errors, you should see the following when submitting our form:
Hello, YOUR-NAME!
Next, add the following function to the end of your Perl script:
sub printMessage {
my $msg = "Hello $first_name $last_name! Did you have $food for lunch?";
print $msg;
}
Update your Perl to call this function so that it correctly prints all the variables we passed in through the HTTP GET request.
After fixing your file, you may consider how to style it with Bootstrap so that it matches the form submission page.
Submission
Submit your Perl script on Gradescope in today’s activity submission form. If you worked in a group, please submit once for the entire group, but be sure to include everyone in the Gradescope submission.
The Gradescope submission will remain open until Friday night.
For a different adventure, try re-writing this example in BASH scripting! You may wish to start with our
example.sh
BASH script.