web-dev-qa-db-ja.com

PHP

PHPで複数のクリックによる複数のフォームの送信を防ぐ方法

18
Marcel

フォームを表示するたびに生成され、1回しか使用できない一意のトークンを使用します。 [〜#〜] csrf [〜#〜] および リプレイ 攻撃を防ぐことも役立ちます。ちょっとした例:

<?php
session_start();

/**
 * Creates a token usable in a form
 * @return string
 */
function getToken(){
  $token = sha1(mt_Rand());
  if(!isset($_SESSION['tokens'])){
    $_SESSION['tokens'] = array($token => 1);
  }
  else{
    $_SESSION['tokens'][$token] = 1;
  }
  return $token;
}

/**
 * Check if a token is valid. Removes it from the valid tokens list
 * @param string $token The token
 * @return bool
 */
function isTokenValid($token){
  if(!empty($_SESSION['tokens'][$token])){
    unset($_SESSION['tokens'][$token]);
    return true;
  }
  return false;
}

// Check if a form has been sent
$postedToken = filter_input(INPUT_POST, 'token');
if(!empty($postedToken)){
  if(isTokenValid($postedToken)){
    // Process form
  }
  else{
    // Do something about the error
  }
}

// Get a token for the form we're displaying
$token = getToken();
?>
<form method="post">
  <fieldset>
    <input type="hidden" name="token" value="<?php echo $token;?>"/>
    <!-- Add form content -->
  </fieldset>
</form>

リダイレクトと組み合わせて、完全な後方および前方の動作を維持します。リダイレクトの詳細については、 POST/redirect/GET パターンを参照してください。

36
Arkh

(JavaScriptを使用して)最初のクリック後にボタンを無効にしたり、バックエンドをチェックして(JavaScriptを無効にした場合に備えて)、最近送信したかどうかを確認することもできます。

バックエンドでチェックを行うには、かなりの数の異なる方法があります。 1つの方法は、セッション変数を最初にクリックしたときに設定することです。これにより、システムに処理中であることを知らせることができます。 2回目、3回目、または4回目のクリックの場合は、セッション変数を確認するだけで、すでにクリックされていることを示している場合は処理されません。

これはほんの一例です-それを出発点として使用できます。

6
xil3

一時的なネットワークの問題(つまり、リクエストがまったく処理されていない)の場合、ユーザーが送信を中止することを選択した場合(Escキー/停止ボタン)、ネットワークで一度送信すると再度送信できないため、送信ボタンを無効にしないことをお勧めしますサービスが復元されました。代わりに、ページを再読み込みしてallフォームエントリに再度入力する必要があります。

3
user562374

あなたはこのようなものを追加することができます

<input type="hidden" name="form-token" value="someRandomNumber">

次に、バックエンドで、複数のフォーム送信を識別するための保存方法があります。もちろん、このソリューションには、処理が完了したことがわかっているフォームトークンなどを削除する必要があるため、手荷物があります。

ほとんどの場合、無効化されたフォームは、たとえばボタンを無効にするか、フォーム送信イベントにreturn falseを追加することによってトリックを実行します(ただし、これがjQueryなしで機能するかどうかはわかりません)。

1
Mike

私はaction.phpで次のことをしています

if($_SESSION && isset($_SESSION['already_submitted'])) {

  # If already submitted just redirect to thank you page

} else {

    # If first submit then assign session value and process the form
    $_SESSION['already_submitted'] = true;

    # Process form

}

注:常にsession_start()を使用してヘッダーでセッションを開始してください。

0
Robert Sinclair

クリック時にボタンを非表示にできますか?フォームの処理には影響しませんが(問題はボタンをすぐに無効にすることであることがわかっているため)、基本的に同じことを行います。本当に心配な場合は、実際には何もしない別のボタンを表示することもできます。型破りな回避策かもしれませんが、それでも回避策です。

0
Carolyn

これはあなたの問題に対する最も一般的な答えです

if (isset($_COOKIE['FormSubmitted']))
{
    die('You may only submit this form once per session!');
}
0
Paulo Rodrigues