Accessing form POST data

M

Mark

I'm not a Perl expert yet (mainly PHP) but as I need to use a little bit of
Perl for a website so I basically copied this code available on several web
tutorials (so I am guessing it is the standard way of doing it). I'm not
totally clear how it works but I can follow the gist. However, I am having
trouble accessing the POST variables that are posted to my page from another
form on a different server. The code just displays a blank.

This is the code I am using copied from the tutotial:

#!/usr/bin/perl

# orderform.cgi

read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
@pairs = split(/&/, $buffer);
foreach $pair (@pairs)
{
($name, $value) = split(/=/, $pair);
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$Form{$name} = $value;
}

print <<END_of_multiline_text;
Content-Type: text/html; charset=ISO-8859-1

.. . .

<p>Your order is worth a total of:
<strong>&pound;$Form{'grandtotal'}</strong></p>

.. . .

END_of_multiline_text;



BTW, I've also been warned that this code leaves me open to a DoS attack and
to use CGI.pm. If anyone would be so kind as to explain how this attack
works I would be interested. Not that I wish to attack anyone! I just want
to be educated about the security issues in Perl. Perhaps it would be better
to post this to me personally at mjtech_uk aaatttt yahoo.co.uk

Thanks v. much
Mark
 
G

Gunnar Hjalmarsson

Mark said:
I basically copied this code available on several web tutorials (so
I am guessing it is the standard way of doing it).

It was a common way to do it ten years ago or so...
I'm not totally clear how it works but I can follow the gist.

Never use a random piece of code copied from the web if you are not
sure of how it works!!
However, I am having trouble accessing the POST variables that are
posted to my page from another form on a different server. The code
just displays a blank.

This is the code I am using copied from the tutotial:

#!/usr/bin/perl

# orderform.cgi

read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
@pairs = split(/&/, $buffer);
foreach $pair (@pairs)
{
($name, $value) = split(/=/, $pair);
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$Form{$name} = $value;
}

print <<END_of_multiline_text;
Content-Type: text/html; charset=ISO-8859-1

. . .

<p>Your order is worth a total of:
<strong>&pound;$Form{'grandtotal'}</strong></p>

. . .

END_of_multiline_text;
-----------------------^

Besides that semicolon, which causes a compile time error and shall
not be there (unlike in PHP), there is nothing obviously wrong with
the above code. What does the form look like? Maybe there is no
"grandtotal" control in the form?

Nevertheless, as others have mentioned in another group, you'd better
use CGI.pm instead. Doing so, the above code could be replaced with:

#!/usr/bin/perl -T
use strict;
use warnings;

use CGI;

my $query = new CGI;
my %Form = $query->Vars;

print $query->header;

print <<END_of_multiline_text;

.. . .

<p>Your order is worth a total of:
<strong>&pound;$Form{'grandtotal'}</strong></p>

.. . .

END_of_multiline_text

__END__
BTW, I've also been warned that this code leaves me open to a DoS
attack and to use CGI.pm. If anyone would be so kind as to explain
how this attack works I would be interested.

The lack of a check of the size of the POSTed data makes it possible
to submit a huge amount of data and have your script process it. This
is a security issue whenever users submit data via a form, not only a
Perl issue, and using CGI.pm doesn't automatically prevent it.

If you use CGI.pm, you can add e.g.

$CGI::pOST_MAX = 1024 * 100; # 100 KiB limit

before the "my $query = new CGI;" line.
Not that I wish to attack anyone! I just want to be educated about
the security issues in Perl. Perhaps it would be better to post
this to me personally at ...

Why? Wouldn't security issues be of general interest? ;-)
 
B

Bob Walton

Mark said:
I'm not a Perl expert yet (mainly PHP) but as I need to use a little bit of
Perl for a website so I basically copied this code available on several web
tutorials (so I am guessing it is the standard way of doing it). I'm not
totally clear how it works but I can follow the gist. However, I am having
trouble accessing the POST variables that are posted to my page from another
form on a different server. The code just displays a blank.

This is the code I am using copied from the tutotial:

#!/usr/bin/perl

# orderform.cgi

read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
@pairs = split(/&/, $buffer);
foreach $pair (@pairs)
{
($name, $value) = split(/=/, $pair);
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$Form{$name} = $value;
}

print <<END_of_multiline_text;
Content-Type: text/html; charset=ISO-8859-1

. . .

<p>Your order is worth a total of:
<strong>&pound;$Form{'grandtotal'}</strong></p>

. . .

END_of_multiline_text;

BTW, I've also been warned that this code leaves me open to a DoS attack and
to use CGI.pm. If anyone would be so kind as to explain how this attack
works I would be interested. Not that I wish to attack anyone! I just want
to be educated about the security issues in Perl. Perhaps it would be better
to post this to me personally at mjtech_uk aaatttt yahoo.co.uk ....
Mark

Those that told you to

use CGI;

were well-informed. The broken crappy code you posted doesn't even
recognize that ; is a valid parameter separation character, in addition
to & , for example. It doesn't check to see if the parameters are
presented via the GET or POST method, or whether a different request was
made (HEADER, perhaps?). It is missing 'use warnings;' and 'use
strict;' -- let Perl help you all it can. As for denial of service
attacks, consider what happens if someone hits your site and keeps
dumping bigger and bigger parameter datasets your way. Eventually,
you'll run out of virtual memory and crash. I'm sure there are other
vulnerabilities as well.

Using CGI is also much easier:

use CGI qw:)standard);
#during development, put Perl errors to the browser
#(*very* most helpful):
use CGI::Carp qw(fatalsToBrowser);
use strict;
use warnings;
print header; #does Content-type header
print start_html('title');
#...
my $grandtotal=param('grandtotal'); #retrieves parameter
print <<EOT;
....
<strong>&pound;$grandtotal</strong>
....
EOT
print end_html;

And you can debug it offline by just supplying parameter pairs as
arguments to your script, like:

perl script.pl grandtotal=123.45

See what you're missing?
 
T

Tad McClellan

Mark said:
I am having
trouble accessing the POST variables that are posted to my page from another
form on a different server.


perldoc -q CGI

How do I decode a CGI form?
 
S

Seungbeom Kim

Bob said:
The broken crappy code you posted doesn't even
recognize that ; is a valid parameter separation character, in addition
to & , for example.

This might be out of topic, but I'm curious which document specifies
that ';' is a valid parameter separation character in addition to '&'.
I couldn't find it in the CGI/1.1, CGI/1.2 specifications.
 
G

Gunnar Hjalmarsson

Seungbeom said:
This might be out of topic, but I'm curious which document
specifies that ';' is a valid parameter separation character in
addition to '&'. I couldn't find it in the CGI/1.1, CGI/1.2
specifications.

It's not. But ';' is often used in query-strings.

Now, an URL with a query-string results in a GET request, while the
original subject of this thread made clear that the OP asked about
POST requests. Accordingly, the code posted by the OP is not "broken"
because of only recognizing '&' as a param separator. It's not
"broken" for any other reason either, but it probably does what it's
supposed to do just fine.

However, in this group people often post comments like that, blunting
the intellect. They do it in order to let you know that you are a
moron if you don't use CGI.pm (or possibly some other module/library)
for parsing CGI data. To make their point, they typically claim that
code like the one the OP posted is "broken" since it doesn't handle
various things that it was never supposed to handle. Often they also
mention irrelevant security aspects. An example of the latter is that
Bob mentioned denial of service attacks, and then he posted code that
is just as exposed to such attacks as the code the OP had posted...

Consequently, beware of this group if you want to *learn* something
about CGI, other than 1) it's off topic here and 2) you should use CGI.pm.

Now, there are good, perfectly valid reasons for using CGI.pm, just as
there are good reasons for using other modules when feasible. It's a
shame IMO that people advocating the use of the module can't stick to
those reasons.
 
J

Jürgen Exner

Gunnar Hjalmarsson wrote:
[...]
Consequently, beware of this group if you want to *learn* something
about CGI, other than 1) it's off topic here and 2) [...].

AMEN to that!

jue
 
B

Bob Walton

Seungbeom said:
This might be out of topic, but I'm curious which document specifies
that ';' is a valid parameter separation character in addition to '&'. I
couldn't find it in the CGI/1.1, CGI/1.2 specifications.

Well, I don't know what document it is specified in, but there is a
discussion about it in the docs for the CGI module:

perldoc CGI

in the "PRAGMAS" section, under the -newstyle_urls and -oldstyle_urls
pragmas, and stuff in the CGI.pm code itself. There are lots of web
references to the & pair separator being deprecated and replaced with ;
as the separator. Maybe someone in a CGI-oriented newsgroup would know
better where this appears in the standards?
 
B

Bob Walton

Gunnar said:
It's not. But ';' is often used in query-strings.


Hmmmm...check out:

perldoc CGI

in the PRAGMAS section under the -newstyle_urls and -oldstyle_urls pragmas.


....
Bob mentioned denial of service attacks, and then he posted code that
is just as exposed to such attacks as the code the OP had posted...


True, but easily fixed with the addition of

$CGI::pOST_MAX=100000;

or so at the beginning of the script, as one can note in

perldoc CGI

in the "Avoiding Denial of Service Attacks" section. My code was
intended to illustrate the ease of using the CGI module, but would have
been better with that addition.
Consequently, beware of this group if you want to *learn* something
about CGI, other than 1) it's off topic here and 2) you should use
CGI.pm.

Agreed. Point well made.


....
 
G

Gunnar Hjalmarsson

Bob said:
True, but easily fixed with the addition of

$CGI::pOST_MAX=100000;

or so at the beginning of the script,

Yes, or without CGI.pm by simply doing something like this:

unless ( $ENV{CONTENT_LENGTH} > 100000 ) {
# read STDIN and parse the data
} else {
# do something else
}

But you stripped the context in which I made that comment. You brought
up the risk for DoS attacks as a reason for using CGI.pm (which it
isn't), followed by code that included "use CGI" etc. but without any
limitation of POSTed data. By doing so, you sent the incorrect message
to the readers of this group that if they only use CGI.pm, they are
protected against DoS attacks. (Joe S. made a similar incorrect
comment in comp.lang.perl in reply to the same OP.)

That's nothing but desinformation, and since we are talking about a
significant *security* issue that people are made believe is
automatically taken care of by CGI.pm, it's the worst kind of
desinformation!

Bob, Joe, and (previously) several other regulars: Why do you
repeatedly do that? Why??
Agreed. Point well made.

Do you really think so? I doubt it was, since I failed to include that
you should not only expect to not learn CGI, but in addition to that
you should be aware of *incorrect* statements about CGI being made
frequently, also by knowledgable regulars. :(

Many posters here seem not to want to discuss Perl programs that are
to be used in a CGI context. That's fine. But then they'd better keep
their mouths shut rather than posting desinformation.
 
S

Sherm Pendley

Bob said:
as the separator. Maybe someone in a CGI-oriented newsgroup would know
better where this appears in the standards?

I think that part of the problem is that there is no CGI "standard" as
such. The closest thing we have to one is NCSA's original documentation:

<http://hoohoo.ncsa.uiuc.edu/cgi/>

There appears to have been an attempt made to organize and submit an RFC
to the IETF, thus creating a formal standard, but that attempt appears
to have died on the vine:

<http://cgi-spec.golux.com/>

sherm--
 
A

Alan J. Flavell

I know this is the wrong place; but as the topic has come up, I think
this is worth saying, if you'll excuse me:

I think that part of the problem is that there is no CGI "standard" as
such. The closest thing we have to one is NCSA's original documentation:

<http://hoohoo.ncsa.uiuc.edu/cgi/>

It's a respectable point of view, don't get me wrong, but those old
NCSA specs are a bit chatty and vague...
There appears to have been an attempt made to organize and submit an RFC
to the IETF, thus creating a formal standard, but that attempt appears
to have died on the vine:

<http://cgi-spec.golux.com/>

It has stopped proceeding to a more-formal stage, fair comment; but
the CGI/1.1 draft had as its goal:

Goal: Clearly and concisely codify "current practice" of CGI/1.1
usage on the Web as of 2000.

and I'd say it has achieved that goal well. I would definitely
recommend consulting it as a reliable source of "current practice",
irrespective of its position on the IETF's greasy pole. IMHO.

But the issue of using semi-colon as the alternative delimeter in
composed GET URLs is codified in the *HTML* specifications, starting
with RFC1866/HTML2.0. The CGI specification does not go into detail
about the format of the QUERY_STRING, but cites other relevant
specifications for it. With POST, on the other hand, the problem
simply doesn't arise for which the semi-colon is the suggested
solution, and so no solution is really needed.

I'd better shut up now.
 
J

Joe Schaefer

[...]
With POST, on the other hand, the problem
simply doesn't arise for which the semi-colon is the suggested
solution, and so no solution is really needed.

FYI: the semicolon is the default separator for the (deprecated)
urlencoded-post method described in the XForms 1.0 spec.

http://www.w3.org/TR/xforms/slice11.html#serialize-urlencode

Earlier drafts mandated ';' as the separator, however the spec
authors eventually recognized that decision was problematic for
POST, so they allowed the separator to be configurable by the form
author to either ';' or '&'.

Allowing ';' as the separator is a good idea anyways, since
it lets future XForms authors make use of your script without
having to fuss over the choice of separator.
 
S

Seungbeom Kim

Alan said:
But the issue of using semi-colon as the alternative delimeter in
composed GET URLs is codified in the *HTML* specifications, starting
with RFC1866/HTML2.0. The CGI specification does not go into detail
about the format of the QUERY_STRING, but cites other relevant
specifications for it. With POST, on the other hand, the problem
simply doesn't arise for which the semi-colon is the suggested
solution, and so no solution is really needed.

The HTML 4.01 Specification still mentions only '&' as the separation
character: http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1

Sorry for continuing this topic here, but many people have responded and
shown interest about this, so I ask for your understanding.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top