
近年、Webサイトに対する攻撃手法は複雑化しており、お問い合わせフォームのセキュリティ対策は盤石にしておく必要があります。
この記事では、お問い合わせフォームのセキュリティ対策(CSRF対策)に関して、その考え方と実装方法について説明します。
1. お問い合わせフォームのセキュリティ対策
お問い合わせフォーム(図1-1)より入力した情報(お名前、メールアドレス、題名、お問い合わせ内容)は、メール送信ボタンを押下することにより、同一ドメインにあるPHPのメール送信プログラムに引き渡され処理されます。
ただ、メール送信プログラムへのデータの引き渡しは、同一ドメインのお問い合わせフォームからではなく、やろうと思えば、他のドメインからでもできてしまいます。
このような、他のドメインから自サイトの処理プログラムにデータを送信して処理させるといった攻撃手法をクロスサイトリクエストフォージェリ(CSRF)といいます。
この記事では、お問い合わせフォームおよびメール送信プログラムにCSRF対策を実装する方法について説明します。
お問い合わせフォームの実装方法については、以下の記事をご覧ください。以下の記事では、固定のトークン認証により、特定フォームからの要求であることをチェックしています。しかし、セキュリティ的にはザルですので、本記事の対策を組み込むことで、お問い合わせフォームのセキュリティ強化につながると考えます。

2. CSRF対策の考えと行うべきこと
(2)なりすましによるメール送信プログラムへの要求をブロックするしくみであること
①自サイトのお問い合わせフォームページで、ランダムな文字列からなるトークンを発行する
②フォームに入力した内容が送信される際には①で発行したトークンもセットで送信されるようにする
③メール送信プログラムはトークンが自サイトで発行されたものかどうかをチェックする
④自サイトで発行されたトークンであればメール送信を行う
3. お問い合わせフォームのCSRF対策
CSRF対策のため追加した部分の説明(コード内番号)は、以下のとおりです。
②文字コードを指定:明示的に文字コード(utf-8)を指定
③クリックジャッキング対策:フレーム内のページ表示を同一ドメイン内のみ許可する指定
④疑似乱数のバイト文字列生成:openssl_random_pseudo_byte(16)関数により生成
⑤バイナリのデータを16進表現に変換:bin2hex()関数による変換
⑥生成したランダムな文字列をセッション変数に設定:$_SESSION[‘csrf_token’] に保存
⑦生成したランダムな文字列をトークン文字列に設定:入力データとして”php/mailer.php”に送る
<?php
//セッションを開始 ・・・➀
session_start();
//文字コード指定 ・・・➁
header("Content-type: text/html; charset=utf-8");
//クリックジャッキング対策 ・・・➂
header('X-FRAME-OPTIONS: SAMEORIGIN');
//疑似乱数のバイト文字列(16バイト)を生成 ・・・➃
$token_byte = openssl_random_pseudo_bytes(16);
//バイナリのデータを16進表現に変換 ・・・➄
$csrf_token = bin2hex($token_byte);
//セッション変数設定 ・・・➅
$_SESSION['csrf_token'] = $csrf_token;
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1" />
<script type="text/javascript" charset="UTF-8"></script>
<title>お問い合わせフォーム</title>
<link rel="stylesheet" href="css/layout.css">
<script src="//code.jquery.com/jquery-2.2.4.min.js"></script>
<script>
//共通パーツ読み込み
$(function() {
$("#header").load("common/header.html");
$("#sidebar").load("common/sidebar-non.html");
$("#footer").load("common/footer.html");
});
</script>
</head>
<body background=image/sozai/hh0430.gif>
<!-- HEADER -->
<div id="header"></div>
<!-- MAIN CONTENTS -->
<div id="container">
<div id="content">
<div id="inner-content" class="clearfix">
<main id="main">
<br/>
<form method="POST" action="php/mailer.php">
<input type="hidden" name="csrf_token" value="<?=$csrf_token?>"> ・・・➆
<div class="form">
<p><font size="4"><b>お名前</b></font></p>
<input type="text" name="name" />
<p><font size="4"><b>メールアドレス</b></font></p>
<input type="text" name="email" />
<p><font size="4"><b>題名</b></font></p>
<input type="text" name="subject" />
<p><font size="4"><b>お問い合わせ内容</b></font></p>
<textarea name="message"></textarea><br>
</div>
<br/>
<div class="contact-submit">
<input type="submit" value="送信">
</div>
</form>
</main>
<!-- SIDEBAR -->
<div id="sidebar"></div>
</div><!-- /#inner-content -->
</div><!-- /#content -->
<br/><br/>
<!-- FOOTER -->
<div id="footer"></div>
</body>
</html>
4. メール送信プログラムのCSRF対策
これにより、なりすましによるメール送信プログラムへの要求をブロックすることができます。
②お問い合わせフォームから送られたトークン文字列とセッション変数に保存されているトークン文字列とを比較
一致 :メール送信処理を継続
不一致:メール送信処理を中止
<?php
//セッションを開始 ・・・➀
session_start();
// パラメータ取得
$request_param = $_POST;
// お問い合わせ日時
$request_datetime = date("Y年m月d日 H時i分s秒");
//自動返信メール
$mailto = $request_param['email'];
$to = '自身のメールアドレス'; //ここを入力
$mailfrom = "From:自身のメールアドレス"; //ここを入力
//問い合わせ相手への送信メール
$subject1 = "お問い合わせ有難うございます。";
$content = "";
$content .= $request_param['name']. "様\r\n";
$content .= "お問い合わせ有難うございます。\r\n";
$content .= "お問い合わせ内容は下記通りでございます。\r\n";
$content .= "=================================\r\n";
$content .= "お名前 " . htmlspecialchars($request_param['name'])."\r\n";
$content .= "メールアドレス " . htmlspecialchars($request_param['email'])."\r\n";
$content .= "題名 " . htmlspecialchars($request_param['subject'])."\r\n";
$content .= "内容 " . htmlspecialchars($request_param['message'])."\r\n";
$content .= "お問い合わせ日時 " . $request_datetime."\r\n";
$content .= "=================================\r\n";
//管理者確認用メール
$subject2 = "お問い合わせがありました。";
$content2 = "";
$content2 .= "お問い合わせがありました。\r\n";
$content2 .= "お問い合わせ内容は下記通りです。\r\n";
$content2 .= "=================================\r\n";
$content2 .= "お名前 " . htmlspecialchars($request_param['name'])."\r\n";
$content2 .= "メールアドレス " . htmlspecialchars($request_param['email'])."\r\n";
$content2 .= "題名 " . htmlspecialchars($request_param['subject'])."\r\n";
$content2 .= "内容 " . htmlspecialchars($request_param['message'])."\r\n";
$content2 .= "お問い合わせ日時 " . $request_datetime."\r\n";
$content2 .= "================================="."\r\n";
mb_language("ja");
mb_internal_encoding("UTF-8");
//mail 送信
if (isset($_POST["csrf_token"]) ・・・➁
&& $_POST["csrf_token"] === $_SESSION['csrf_token']) { ・・・➁
if( filter_var( $mailto, FILTER_VALIDATE_EMAIL ) ){
if(mb_send_mail($to, $subject2, $content2, $mailfrom)){
mb_send_mail($mailto,$subject1,$content,$mailfrom);
?>
<script>
window.location = '../mail-send-end.html';
</script>
<?php
} else {
header('Content-Type: text/html; charset=UTF-8');
echo "メールの送信に失敗しました";
};
} else {
header('Content-Type: text/html; charset=UTF-8');
echo "メールアドレスの形式が正しくありません";
};
} else {
echo "メールの送信に失敗しました(トークンエラー)";
}
?>
5. まとめ
お問い合わせフォームは、実際にサイト閲覧者に対しメールを送信することになりますので、悪用されることがあってはなりません。セキュリティ強化のためにCSRF対策を検討されている方に、この記事がすこしでも参考となれば幸いです。

現在では、WordPress等のWeb制作ツールを用いて、HTMLやCSSなどの専門的な知識がなくてもWebサイトを制作することが可能ですが、パフォーマンスやセキュリティの優位性等から、官公庁や企業サイトなどの静的サイト制作需要はなくなりません。
もし、静的サイト制作に不可欠なHTML、CSS、Java Script等を本腰を入れて学びたいという方がいらっしゃるのであれば、
以下を無料で体験して感触を掴んでみてはどうでしょうか。


コメント