掲示板 その2 - CGI(Perl)の基本と掲示板作成
目次
掲示板 その2
ここまでのプログラムで、最も基本的な一行掲示板は完成しました。しかし掲示板として公開するには、セキュリティ対策を行なわなければなりません。前回までの掲示板では、フォームの内容がノーチェックでHTMLとして表示されるため、さまざまな攻撃を受ける可能性があります。自分のサイトだけが攻撃を受けるのならばまだしも、JavaScriptなどを組み合わせると他人のサイトにまで攻撃が及ぶ可能性があります。今回行なうこと
- セキュリティ対策
- 名前欄の追加
- ファイルのロック
プログラム
以下のプログラムをテキストエディタで入力してください。bbs1.cgiをコピーして変更部分のみを追加・修正すれば良いでしょう。
#!/usr/bin/perl
# 掲示板 その2
require "cgi-lib.pl";
print "Content-type: text/html; charset=Shift_JIS\n\n";
# フォーム部分を表示する
print <<EOL;
<html>
<body>
<h2>一行掲示板</h2>
<form method="post" action="bbs2.cgi">
名前:<input type="text" name="namae" size="20">
メッセージ:<input type="text" name="message" size="60">
<input type="submit" value="送信">
</form>
<hr>
EOL
&ReadParse(*form);
# フォームの値を取得
$namae = $form{"namae"};
$message = $form{"message"};
# ログファイル読み込み
open(IN, "bbs2.txt");
@log = <IN>;
close(IN);
# メッセージが入力されているときは書き込み処理を行なう
if ($message ne "") {
# タグの無効化
$namae =~ s/</</g;
$namae =~ s/>/>/g;
$message =~ s/</</g;
$message =~ s/>/>/g;
# ログ先頭に名前とメッセージを格納
unshift @log, "$namae\t$message\n";
# ログファイルにロックをかけて書き込み
open(OUT, "+< bbs2.txt");
flock(OUT, 2);
truncate(OUT, 0);
seek(OUT, 0, 0);
print OUT @log;
close(OUT);
}
# ログ表示
foreach $data (@log) {
chop $data;
($namae, $message) = split(/\t/, $data);
print "[$namae] $message<br>\n";
}
print "</body>\n</html>\n";
入力が終わったら、「bbs2.cgi」という名前でサーバにアップロードし、パーミッションを755にしてください。さらに空のログファイル「bbs2.txt」をサーバにアップロードし、パーミッションを666(読み書き可能)にしてください。その後bbs2.cgiが動くかブラウザで確認してください。
プログラムの説明
# タグの無効化
$namae =~ s/</</g;
$namae =~ s/>/>/g;
$message =~ s/</</g;
$message =~ s/>/>/g;
ここがセキュリティに関する部分です。掲示板を攻撃されないための最も手っ取り早い方法は、フォームで送られてきたデータの全てのタグを無効にすることです。ここではタグを無効化するために、Perlの正規表現という機能を使います。今回使っているのは以下のような書き方です。
変数名 =~ s/文字列1/文字列2/g;
この書き方によって、変数の中にある全ての文字列1を文字列2に置換することができます。1行目は$namaeの中にある「<」を「<」に変換し、2行目は$namaeの中にある「>」を「>」に変換します。これによってタグを無効化できるのです。
unshift @log, "$namae\t$message\n";
前回は保存するデータがメッセージしか無かったので、一行にそれだけを書けばよかったのですが、今回は名前が入ったので名前とメッセージの両方を保存しなければなりません。一行で名前とメッセージを保存するには、間になんらかの区切りがないと判別できなくなります。そこで今回はタブを区切り文字としました。タブは画面上では見えないので「\t」という特別な書き方をします。
open(OUT, "+< bbs2.txt");
今回はファイルにロックをかけます。ロックとは鍵のことで、ファイルを操作しているときに他人に同じファイルを操作されないようにする機能です。「+<」という記号を付けてファイルをオープンすると、ファイルを読み書き両方できるモードで開くことができます。ロックを使うときにはこのモードでなければ確実なロックができません。
flock(OUT, 2);
この文が、実際にファイルにロックをかけている部分です。ここからファイルハンドルをクローズするまでは、他の人はこのファイル(bbs2.txt)を操作することはできません。
truncate(OUT, 0);
seek(OUT, 0, 0);
ファイルのサイズを0にしてファイルの先頭に移動する命令です。ロックを使うときは面倒ですがこうしておかないと、確実なロックができません。
close(OUT);
ファイルハンドルがクローズされるときにロックも解除されます。
($namae, $message) = split(/\t/, $data);
split命令は文字列を指定した区切り文字で区切る機能を持ちます。このソースでは、$dataに入っている文字列をタブで区切り、区切られたひとつ目の値を$namaeに、二つ目の値を$messageに代入しています。