こんにちは!セミマサです。
以前作成したお問い合わせフォームにセキュリティ対策をしました!この記事で詳細をまとめたいと思います。
※CSSは変化がないのでこの記事には掲載していません。過去記事をご確認ください!
メインとなるform.php
<?php
session_start();
$rand = openssl_random_pseudo_bytes(32);
$token = bin2hex($rand);
$_SESSION['token'] = $token;
?>
<section>
<div class="inner">
<h2 class="heading">お問い合わせはこちら</h2>
<p><span class="red">※</span>は必須項目です。</p>
<form id="contact-form">
<input type="hidden" name="token" value="<?=$token?>">
<label class="form-label">お名前<span class="red">※</span></label>
<input type="text" name="name" value="" placeholder="お名前" required>
<label class="form-label">メールアドレス<span class="red">※</span></label>
<input type="email" name="email" value="" placeholder="メールアドレス" pattern="[\w\d_-]+@[\w\d_-]+\.[\w\d._-]+" title="メールアドレスは、aaa@example.com のような形式で記入してください。" required>
<label class="form-label">お問い合わせ内容<span class="red">※</span></label>
<textarea name="message" cols="40" rows="10" placeholder="お問い合わせ内容" required></textarea>
<input type="submit" value="送信" class="send-btn" id="submit">
</form>
<p class="contact-result"></p>
</div>
</section>
フォームを表示するphpです。CSRF対策としてトークンを使うことにしました。1~6行目がそのために追加した処理です。
・openssl_random_pseudo_bytes(32)で32桁の疑似乱数を生成して変数randに代入。
・bin2hexでrandを16進表記に変換して変数tokenに代入。
・変数tokenをセッション変数に登録
変数tokenはhiddenパラメータとしてformにも埋め込んでおきます。(12行目)
・件名の入力欄はなくても問題ないと思ったので削除しました。
送信処理を行うsend.php
<?php
session_start();
if(isset($_POST["token"]) && $_POST["token"] === $_SESSION['token']){
$name =filter_input(INPUT_POST, 'name',FILTER_SANITIZE_SPECIAL_CHARS);
$email = filter_input(INPUT_POST, 'email',FILTER_SANITIZE_EMAIL);
$subject = $name.'様からのお問い合わせ';
$message = filter_input(INPUT_POST, 'message',FILTER_SANITIZE_SPECIAL_CHARS);
$complete_msg = '';
$to = 'ここに送り先のアドレスを入れる';
$from = '送信元アドレスを入れる';
$headers = "From: ".$from."\r\n";
$message .= "\r\n\r\n".$name."\r\n\r\n".$email;
mb_language('Japanese');
mb_internal_encoding("UTF-8");
mb_send_mail($to,$subject,$message,$headers);
$complete_msg = '送信されました!';
echo $complete_msg;
$name = '';
$email = '';
$subject = '';
$message = '';
}else{
echo '不正なリクエストです';
}
?>
こちらはメール送信を担当するphpです。意識した点は可能な限り外部パラメータを減らすこと。
最初の条件分岐について
ポストされたtokenにNULLではない値が入っていて、かつセッション変数に登録した値と等しい場合処理を継続するようにしています。
isset:値がセットされており、NULLでないことをチェックする
処理内容
前回からの変更点は下記になります。
・subject,from,headersを固定値にしました。emailはメール本文であるmessageに移しています。
・name,email,messageを$_POSTではなくfilter_inputで受け取るようにしました。その際にemailは FILTER_SANITIZE_EMAILで、nameとmessageはFILTER_SANITIZE_SPECIAL_CHARSを用いてエスケープ処理をしています。
・文字化け回避のためにmb_languageで言語、mb_internal_encodingで文字コードを指定しました。
jQuery
<script>
$('#contact-form').submit(function(event){
event.preventDefault();
var $form = $(this);
var $button = $('#submit');
$.ajax({
url:"send.php",
type:'POST',
data: $form.serialize(),
timeout:10000,
beforeSend: function(xhr, settings) {
$button.attr('disabled', true);
},
complete: function(xhr, textStatus) {
$button.attr('disabled', false);
}
}).done(function(data, textStatus, jqXHR){
// 成功の場合処理
$form[0].reset();
$(".contact-result").text(data);
$(".contact-result").slideToggle(200);
$(".contact-result").delay(3000).slideToggle(200);
}).fail(function(jqXHR, textStatus, errorThrown){
// エラーの場合処理
$(".contact-result").text("エラーが発生しました。ステータス:" + jqXHR.status);
$(".contact-result").slideToggle(100);
$(".contact-result").delay(3000).slideToggle(200);
});
});
</script>
変更を加えたのは7・8行目です。ajax内のurlとtypeを直接指定しています。
おわりに
以前作成したお問い合わせフォームに思いつく限りのセキュリティ対策をしてみました。動作は確認済みです。