But if I avoid eval(), exec(), popen() and system(), how can I create an interface to my database/search engine/graphics package?
You don't have to avoid these calls completely. You just have to understand what you're doing before you call them. In some cases you can avoid passing user-supplied variables through the shell by calling external programs differently. For example, sendmail supports a -t option, which tells it to ignore the address given on the command line and take its To: address from the e-mail header. The example above can be rewritten in order to take advantage of this feature as shown below (it also uses the -oi flag to prevent sendmail from ending the message prematurely if it encounters a period at the start of a line):
$mailto = &get_name_from_input; # read the address from form open (MAIL,"| /usr/lib/sendmail -t -oi"); print MAIL <<END; To: $mailto From: me (me\@nowhere.com) Subject: nothing much
Hi there! END close MAIL;
C programmers can use the exec family of commands to pass arguments directly to programs rather than going through the shell. This can also be accomplished in Perl using the technique described below.
You should try to find ways not to open a shell. In the rare cases when you have no choice, you should always scan the arguments for shell metacharacters and remove them. The list of shell metacharacters is extensive:
&;`'\"|*?~<>^()[]{}$\n\r
Notice that it contains the carriage return and newline characters, something that someone at NCSA forgot when he or she wrote the widely-distributed util.c library as an example of CGI scripting in C.
It's a better policy to make sure that all user input arguments are exactly what you expect rather than blindly remove shell metacharacters and hope there aren't any unexpected side-effects. Even if you avoid the shell and pass user variables directly to a program, you can never be sure that they don't contain constructions that reveal holes in the programs you're calling.
For example, here's a way to make sure that the $mail_to address created by the user really does look like a valid address:
$mail_to = &get_name_from_input; # read the address from form unless ($mail_to =~ /^[\w.+-]+\@[\w.+-]+$/) { die 'Address not in form foo@nowhere.com'; }
(This particular pattern match may be too restrictive for some sites. It doesn't allow UUCP-style addresses or any of the many alternative addressing schemes).
0 comments, (580 reads) All Articles by, GentleGiant