PerlでCGIスクリプトを書く場合はCGIモジュールを使うことが一般的です。まずは簡単なサンプルから。
#!/usr/bin/perlusev5.30.0;usewarnings;useCGI;my$title="Simple Sample";my$q=CGI->new;print$q->header(-type=>'text/html',-charset=>'utf-8');sayCGI::htmlCGI::head(CGI::title$title),CGI::body(CGI::h1($title),CGI::p"Hello world!");
Content-Type: text/html; charset=utf-8 <html><head><title>Simple Sample</title></head> <body><h1>Simple Sample</h1> <p>Hello world!</p></body></html>
CGIモジュールのheaderメソッドはHTTPレスポンスヘッダを生成するメソッドです。「-type」でContent-Typeヘッダフィールドの値を指定します。また、「-charset」に文字符号化方式を指定すれば、Content-Typeヘッダフィールドの値にcharsetを付与することができます。
クエリ文字列を解析しパラメータを取り出すには、paramメソッドを使う。
useCGI;my$q=CGI->new;my$title=$q->param('title');# ?title=Perl/CGI ならば "Perl/CGI" を返す
paramメソッドにはパラメータ名を渡す。引数なしで呼び出すと、すべてのパラメータ名と値のペアをリストとして返す。
useCGI;my$q=CGI->new;my%param=$q->param();print$param{title};
このように、CGIモジュールを使うことで、CGIスクリプトに必要な処理を簡略化して記述することができます。
CGIスクリプトでエラーが発生した場合、サーバの設定によってはエラーログにエラーの内容が記載されるが、CGI::Carpモジュールを使うとウェブページ上にエラーメッセージを出力することができます。
useCGI::Carpqw(fatalsToBrowser);
fatalsToBrowserをインポートすると、致命的エラーが発生した場合にエラーメッセージを出力します。これにより、CGIスクリプトのデバッグが容易になります。
warningsToBrowserを呼び出すと、致命的でない警告メッセージをHTMLのコメントとして出力することができます。
usewarnings;useCGI::Carpqw(fatalsToBrowser warningsToBrowser);warningsToBrowser(1);
CGI::Carpはdieやwarnをラップし、それらが呼び出されたときにエラーメッセージをHTMLとして出力する。モジュール内ではCarp、CGIスクリプト内ではCGI::Carpを使うことが推奨される場合があります。
CGIスクリプトでは外部からデータを渡されることが多いが、それらのデータをチェックせずに出力するなどしてクロスサイトスクリプティングなどの脆弱性を生む危険性があります。
perlに-Tスイッチを付けると、taintモードが有効となり、外部から渡された安全性が疑わしいデータを「汚染」されているものと見なす。汚染されたデータを加工せずに出力しようとすると、例外を発生させてスクリプトの動作を中断します。
#!/usr/bin/perl -TuseCGI;my$q=CGI->new;my$text=$q->param('text');# $textは汚染されているmy$copy=$text;# $copyは汚染されている$copy=~s/&/&/g;# $copyは浄化されたprint$copy;# OK
-Tスイッチは脆弱性を完全に防げるものではありません。上記のコードでは、例えばMIMEタイプがtext/htmlの場合、<や>などのHTMLの構文に使われる文字をエスケープする処理を$copyに施していないため、任意の構文を埋め込むことが可能になってしまいます。
このように万全ではないものの、汚染されたデータの使用を抑制することはできるため、外部からデータを受け取るCGIスクリプトでは常に-Tスイッチを有効にすることが推奨されます。