Avoiding Denial of Service Attacks
Avoiding Denial of Service Attacks
This script will save its state to a file of the user's choosing when the
"save" button is pressed, and will restore its state when the "restore" button
is pressed. CGI.pm will attempt to read the entire POST into a variable, growing
hugely in size until it runs out of memory. While the script attempts to
allocate the memory the system may slow down dramatically. This is a form of
denial of service attack.
Another possible attack is for the remote user to force CGI.pm to accept a
huge file upload. CGI.pm will accept the upload and store it in a temporary
directory even if your script doesn't expect to receive an uploaded file. CGI.pm
will delete the file automatically when it terminates, but in the meantime the
remote user may have filled up the server's disk space, causing problems for
other programs.
The best way to avoid denial of service attacks is to limit the amount of
memory, CPU time and disk space that CGI scripts can use. Some Web servers come
with built-in facilities to accomplish this. In other cases, you can use the
shell limit or ulimit commands to put ceilings on CGI resource
usage.
CGI.pm also has some simple built-in protections against denial of service
attacks, but you must activate them before you can use them. These take the form
of two global variables in the CGI name space:
$CGI::POST_MAX
If set to a
non-negative integer, this variable puts a ceiling on the size of POSTings, in
bytes. If CGI.pm detects a POST that is greater than the ceiling, it will
immediately exit with an error message. This value will affect both ordinary
POSTs and multipart POSTs, meaning that it limits the maximum size of file
uploads as well. You should set this to a reasonably high value, such as 1
megabyte.
$CGI::DISABLE_UPLOADS
If set to a
non-zero value, this will disable file uploads completely. Other fill-out form
values will work as usual.
You can use these variables in either of two ways.
- On a script-by-script basis. Set the variable at the top of the script,
right after the "use" statement:
- use CGI qw/:standard/;
- use CGI::Carp
'fatalsToBrowser';
- $CGI::POST_MAX=1024 * 100; # max 100K
posts
- $CGI::DISABLE_UPLOADS = 1; # no
uploads
- Globally for all scripts. Open up CGI.pm, find the definitions for
$POST_MAX and
$DISABLE_UPLOADS, and set them to the
desired values. You'll find them towards the top of the file in a subroutine
named initialize_globals.
Since an attempt to send a POST larger than
$POST_MAX bytes will cause a fatal
error, you might want to use CGI::Carp to echo the fatal error message to the
browser window as shown in the example above. Otherwise the remote user will see
only a generic "Internal Server" error message. See the manual page for
CGI::Carp for more details.
An attempt to send a POST larger than $POST_MAX bytes will cause
param() to return an empty CGI parameter list. You can test for this
event by checking cgi_error(), either after you create the CGI object or,
if you are using the function-oriented interface, call param() for the
first time. If the POST was intercepted, then cgi_error() will return the
message "413 POST too large".
This error message is actually defined by the HTTP protocol, and is
designed to be returned to the browser as the CGI script's status code. For
example:
$uploaded_file =
param('upload');
if (!$uploaded_file && cgi_error())
{
print
header(-status=>cgi_error());
exit 0;
}
Some browsers may not know what to do with this status code. It may be
better just to create an HTML page that warns the user of the problem.
|