=> /blog.gmi ブログ一覧へ # 【PHP】正しい連絡フォームの作り方(クライアント側をぜったいに信用するな!!) 公開日:2023-08-04 ## 問題 現在の「モダン」ウェブ開発で、連絡フォームはJavascriptで制御されていますが、これは大きなリスクがあります。 その理由について、直ぐに説明します。 以下のスクショをご覧いただいたら、何が問題は何だと思いますか? => /static/fuanform1.png 正解は:送信ボタンは`
`タグの外にある事です。 これでは、Javascriptを無効にした場合、送信ボタンをクリックする事が出来ません。 このフォームを送信する為には、この送信ボタンをフォーム内に移動し、`type="button"`を`type="submit"`に変更する事で、Javascriptなしでもフォームを送信する事が可能になります。 そんな感じ: => /static/fuanform2.png そうして、入力画面で「required=""」というパラメータがあり、これによりJavascriptが無効であってもフィールドが入力されているかどうかを確認できます。 例: => /static/fuanform3.png しかし、このパラメータを削除すると、どのような事態が起こると思いますか? 正解はこちら: => /static/fuanform4.png また、確認画面ではフォームが``タグを沢山含んでいます。 その中の「value=""」部分を変更する事が可能です。 これにより、MySQLインジェクションも可能となります。 ## 解決策 上述の問題を解決する為には、サーバー側でのチェックが必要です。 勿論、クライアント側とサーバー側の両方でチェックを行う事も可能です。 例として、PHPの場合を紹介します(PHPを使用するフォームが多い為): ```php true, ]); if (empty($_SESSION["csrf_token"])) $_SESSION["csrf_token"] = bin2hex(random_bytes(32)); if (!isset($_SESSION["step"])) $_SESSION["step"] = 1; $errmes = []; $reqvals = [ "name" => $_SESSION["name"] ?? "", "kana" => $_SESSION["kana"] ?? "", ]; $optvals = [ "url" => $_SESSION["url"] ?? "", ]; if ($_SERVER["REQUEST_METHOD"] == "POST") { if (!hash_equals($_SESSION["csrf_token"], $_POST["csrf_token"])) { die("不正なCSRFトークン"); } if ($_SESSION["step"] == 1) { foreach ($reqvals as $k => $v) { $_SESSION[$k] = filter_input(INPUT_POST, $k, FILTER_SANITIZE_STRING); if ($_SESSION[$k]) $reqvals[$k] = $_SESSION[$k]; else $errmes[] = $k."をご入力下さい。"; } foreach ($optvals as $k => $v) { $_SESSION[$k] = filter_input(INPUT_POST, $k, FILTER_SANITIZE_STRING); $optvals[$k] = $_SESSION[$k]; } if (empty($errmes)) $_SESSION["step"] = 2; } else if ($_SESSION["step"] == 2) { $_SESSION["step"] = 1; session_destroy(); header("Location: /success.html"); die(); } } else { $_SESSION["csrf_token"] = bin2hex(random_bytes(32)); $_SESSION["step"] = 1; } ?> 連絡フォーム
お名前 (必須): " />
お名前 (かな) (必須): " />
御社又は関連サイトのURL: " />
お名前 (必須):
お名前 (かな) (必須):
御社又は関連サイトのURL:

不明なエラー。

``` 結果: => /static/anzenform1.png => /static/anzenform2.png => /static/anzenform3.png => /static/anzenform4.png => /static/anzenform5.png => /static/anzenform6.png ねぇねぇー! 簡単でしょー! 以上