2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【PHP】②お問い合わせフォーム セキュリティ対策

Last updated at Posted at 2023-08-20

最近こんなツイートをしました。もう少し詳しく説明していきます。

この記事ではセキュリティ対策の記事を作成しています。

お問い合わせフォームの実装についての記事

【PHP】①お問い合わせフォーム 実装

バリデーションについての記事

【PHP】③お問い合わせフォーム バリデーション

※[【PHP】①お問い合わせフォーム 実装 ] も同時に実施すると理解度が深まります。

サイトへの攻撃

💡 XSS(Cross-Site Scripting) CSRF など

XSSについて

<>’’ などを無効にする処理をしていきます。

****htmlspecialchars()****

この関数を使って &amp;&gt; などに変換して、<>‘’ などを無効化にすることができます。以下に表を記載しておきます。

変更対象となる文字

変換前 変換後
& (アンパサンド) &
" (ダブルクォート) ENT_NOQUOTES が指定されていない場合、"
' (シングルクォート) ' (ENT_HTML401 の場合) あるいは ' ( ENT_XML1、ENT_XHTML、 ENT_HTML5 の場合)。ただし ENT_QUOTES が指定されている場合に限る
< (小なり) <
> (大なり) >

書き方

return htmlspecialchars($_POST['name'], ENT_QUOTES, 'UTF-8');

$_POST['name'] は文字を指定

ENT_QUOTES シングルクオートとダブルクオートを共に変換

UTF-8 は文字コードを指定

CSRFについて

認証されたユーザーを騙し、知らぬ間に悪意のあるリクエストを送信して、意図しない処理が行われ実行させられてしまう攻撃

フォームを作る際は必ずこのCSRF対策をしていく必要があります。

$_SESSION

$_GET$_POST は送信すると1回きりで消えてしまうのですが、 $_SESSION の場合はずっと残ってくれます。

書き方

session_start();

コードの冒頭に session_start(); と記載してあげればセッションを使うことができます。

暗号の作り方

<?php random_bytes(32); ?>

こちらの関数は、安全なバイト列を生成してくれます。

しかしこのままではうまく使えないので16進数に書き換えていきます。

<?php bin2hex(random_bytes(32)); ?>

手順

セキュリティ対策の実装

[ 【PHP】①お問い合わせフォーム 実装 ] のコードを元にセキュリティ対策を書いていきます。

▼長いのでCtrl+Fで「追加」と検索して調べると追加された箇所を確認できます。

form > input.php

<?php

session_start(); //追加

$pageFlag = 0;
// 入力画面の値が空では無かったら$pageFlagを1に変更
if(!empty($_POST['btn_confirm'])){
    $pageFlag = 1;
}
// 送信画面の値が空では無かったら$pageFlagを2に変更
if(!empty($_POST['btn_submit'])){
    $pageFlag = 2;
}

// 追加
function hsc($str)
{
    return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
}

?>

<!DOCTYPE html>
<meta charset="utf-8">
<head></head>
<body>
    
<!-- 入力画面 -->
<?php if($pageFlag === 0) : ?>

<!-- 追加 -->
<?php
if(!isset($_SESSION['csrfToken']))
{
    $csrfToken = bin2hex(random_bytes(32)); 
    $_SESSION['csrfToken'] = $csrfToken;
}
$token = $_SESSION['csrfToken'];
?>

<form method="POST" action="input.php">

    氏名
    <input type="text" name="name" value="<?php if(!empty($_POST['name'])){ echo hsc($_POST['name']) ; } ?>"><br> <!-- 追加 -->
    メールアドレス
    <input type="email" name="email" value="<?php if(!empty($_POST['email'])){ echo hsc($_POST['email']) ; } ?>"><br> <!-- 追加 -->

    <input type="submit" name="btn_confirm" value="確認する">

    <input type="hidden" name="csrf" value="<?php echo $token; ?>"> <!-- 追加 -->

</form>

<?php endif; ?>
    
    <!-- 確認画面 -->
    <?php if($pageFlag === 1) : ?>
        <?php if($_POST['csrf'] === $_SESSION['csrfToken']) : ?> <!-- 追加 -->
            <form method="POST" action="input.php">

                氏名
                <?php echo hsc($_POST['name']) ;?> <!-- 追加 -->
                <br>

                メールアドレス
                <?php echo hsc($_POST['email']) ;?> <!-- 追加 -->
                <br>

                <input type="submit" name="back" value="戻る">
                <input type="submit" name="btn_submit" value="送信する">

                <input type="hidden" name="name" value="<?php echo hsc($_POST['name']) ;?>"> <!-- 追加 -->
                <input type="hidden" name="email" value="<?php echo hsc($_POST['email']) ;?>"> <!-- 追加 -->
                <input type="hidden" name="csrf" value="<?php echo hsc($_POST['csrf']) ;?>"> <!-- 追加 -->

            </form>
        <?php endif; ?> <!-- 追加 -->
    <?php endif; ?>
    
    <!-- 完了画面 -->
    <?php if($pageFlag === 2) : ?>
        <?php if($_POST['csrf'] === $_SESSION['csrfToken']) : ?> <!-- 追加 -->
            <p>送信が完了しました。</p>

            <?php unset($_SESSION['csrfToken']); ?> <!-- 追加 -->
        <?php endif; ?> <!-- 追加 -->
    <?php endif; ?>

</body>
</html>

セッションの使用

コードの冒頭に session_start(); と記載してあげればセッションを使うことができます。

XSSを関数にする

function hsc($str)
{
    return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
}

$str は文字を指定

ENT_QUOTES シングルクオートとダブルクオートを共に変換

UTF-8 は文字コードを指定

1つ1つにhtmlspecialchars() を書いていくのは面倒なので今回はfunction()関数にしています。

作ったトークンを変数に入れる

<?php $csrfToken = bin2hex(random_bytes(32)); ?>

random_bytes() こちらの関数は、安全なバイト列を生成してくれます。

しかしこのままではうまく使えないので bin2hex() で16進数に書き換えていきます。

作ったトークンを変数 $csrfToken に入れてあげています。

この状態だと入力画面を表示するたびにトークンを作成してしまうので今回はif文で $csrfToken が無かったら作成するという処理を加えています。

if(!isset($_SESSION['csrfToken']))
{
    $csrfToken = bin2hex(random_bytes(32));
		//キー               //バリュー
		$_SESSION['csrfToken'] = $csrfToken;
}
$token = $_SESSION['csrfToken'];

csrfToken が設定されていなかったら $csrfToken を作るようにしています。

$_SESSION['csrfToken']; だと少し長いので変数に入れています。

作った関数を使用する

    氏名
    <input type="text" name="name" value="<?php if(!empty($_POST['name'])){ echo hsc($_POST['name']) ; } ?>"><br> <!-- 追加 -->
    メールアドレス
    <input type="email" name="email" value="<?php if(!empty($_POST['email'])){ echo hsc($_POST['email']) ; } ?>"><br> <!-- 追加 -->

functionで作った関数hsc()を使っている

作ったトークンを仕込んでいく

<input type="hidden" name="csrf" value="<?php echo $token; ?>">

これで value に合言葉が入るようになりました。

トークンが正しいか判定

if($_POST['csrf']) ’csrf’は入力画面のformからとってくる値です。

<?php if($_POST['csrf'] === $_SESSION['csrfToken']) ?> 

で送られてくるトークンと送ったトークンがあっているかの判定をしています。

なのでトークンが同じであれば確認画面を表示するというような処理にしています。

作った関数を使用する

氏名
<?php echo hsc($_POST['name']) ;?> <!-- 追加 -->
<br>

メールアドレス
<?php echo hsc($_POST['email']) ;?> <!-- 追加 -->
<br>

functionで作った関数hsc()を使っている

作った関数を使用する

<input type="hidden" name="name" value="<?php echo hsc($_POST['name']) ;?>"> <!-- 追加 -->
<input type="hidden" name="email" value="<?php echo hsc($_POST['email']) ;?>"> <!-- 追加 -->

functionで作った関数hsc()を使っている

csrfもhiddenで持たせてあげる

<input type="hidden" name="csrf" value="<?php echo hsc($_POST['csrf']) ;?>">

これで消えずに持たせてあげることができました。

完了画面でもトークンが正しいか判定

<?php if($_POST['csrf'] === $_SESSION['csrfToken']) ?> 

で送られてくるトークンと送ったトークンがあっているかの判定をしています。

トークンの削除

<?php unset($_SESSION['csrfToken']); ?>

トークンがずっと残っているとよろしくないのでトークンを削除する処理を記載しています。

この流れでお問い合わせフォームのバリデーションについての記事を読む

【PHP】③お問い合わせフォーム バリデーション処理

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?