ホームページ  >  記事  >  バックエンド開発  >  PHPフォームにトークンを追加して重複送信を防止する方法の解析

PHPフォームにトークンを追加して重複送信を防止する方法の解析

高洛峰
高洛峰オリジナル
2016-12-20 15:52:001036ブラウズ

この記事の例では、繰り返し送信を防ぐために PHP フォームにトークンを追加する方法を説明します。ご参考までに、詳細は以下の通りです:

トークンについて簡単に説明します

トークンはトークンであり、その最大の特徴はランダム性と予測不可能性です。通常のハッカーやソフトウェアはそれを推測できません。

それでは、トークンの機能は何ですか?原理は何ですか?

トークンは一般に 2 つの場所で使用されます - フォームの繰り返し送信と反 csrf 攻撃 (クロスサイト リクエスト フォージェリ) を防ぐためです。

どちらも原則としてセッショントークンを通じて実装されます。クライアントがページをリクエストすると、サーバーは乱数のトークンを生成し、そのトークンをセッションに配置して、そのトークンをクライアントに送信します (通常は非表示のフォームを構築します)。次回クライアントがリクエストを送信すると、トークンがフォームとともにサーバーに送信されます。

その後、「アンチ csrf 攻撃」に適用される場合、サーバーはトークン値を検証して、セッション内のトークン値と等しいかどうかを判断します。等しい場合は、リクエストが有効であることを証明できます。鍛造する。

ただし、「フォームの重複送信防止」を適用した場合、サーバー側での1回目の検証が同じ後、ユーザーが繰り返し送信すると、2回目の検証判定が失敗します。ユーザーが送信したフォームのトークンは変更されていませんが、サーバー側セッションのトークンは変更されているためです。

上記のセッションアプリケーションは比較的安全ですが、同時に、複数のページと複数のリクエストがある場合、複数のトークンを同時に生成する方法を使用する必要があり、より多くのリソースを消費します。実行効率が低下します。したがって、セッショントークンの代わりに検証情報をCookieに格納する方法も利用できます。たとえば、「繰り返し送信」を処理する場合、最初の送信後に送信された情報が Cookie に書き込まれます。2 回目の送信では、Cookie にすでに送信記録があるため、2 回目の送信は失敗します。

ただし、Cookie ストレージには致命的な弱点があります (XSS 攻撃によりユーザーの Cookie が簡単に取得できる) と、再びゲームオーバーになります。ハッカーは直接 CSRF 攻撃を実行します。

PHPフォームにトークンを追加して重複送信を防止する方法の解析

つまり、安全性と効率性は相対的なものです。特定の問題に詳しく対処しましょう。

繰り返しの送信を防ぐために、トークンが PHP フォームに追加されます

原理は、ランダムな文字列を生成し、フォームを送信した後、この文字列を検証することです。これにより、他の人が自分でフォームを作成することを防ぐことができます。提出を不正行為したり、繰り返し提出したり、ダブルクリックして提出したりすること。

PHPフォームにトークンを追加して重複送信を防止する方法の解析

phpで実装された簡単なコードは次のとおりです:

<?php
/*
* PHP简单利用token防止表单重复提交
* 此处理方法纯粹是为了给初学者参考
*/
session_start();
function set_token() {
  $_SESSION[&#39;token&#39;] = md5(microtime(true));
}
function valid_token() {
  $return = $_REQUEST[&#39;token&#39;] === $_SESSION[&#39;token&#39;] ? true : false;
  set_token();
  return $return;
}
//如果token为空则生成一个token
if(!isset($_SESSION[&#39;token&#39;]) || $_SESSION[&#39;token&#39;]==&#39;&#39;) {
  set_token();
}
if(isset($_POST[&#39;test&#39;])){
  if(!valid_token()){
    echo "token error";
  }else{
    echo &#39;成功提交,Value:&#39;.$_POST[&#39;test&#39;];
  }
}
?>
<form method="post" action="">
  <input type="hidden" name="token" value="<?php echo $_SESSION[&#39;token&#39;]?>">
  <input type="text" name="test" value="Default">
  <input type="submit" value="提交" />
</form>

上記の方法はより簡単で、次のコードはより安全です。

Token.php

<?php
/*
 * Created on 2013-3-25
 *
 * To change the template for this generated file go to
 * Window - Preferences - PHPeclipse - PHP - Code Templates
 */
function getToken($len = 32, $md5 = true) {
  # Seed random number generator
  # Only needed for PHP versions prior to 4.2
  mt_srand((double) microtime() * 1000000);
  # Array of characters, adjust as desired
  $chars = array (
    &#39;Q&#39;,
    &#39;@&#39;,
    &#39;8&#39;,
    &#39;y&#39;,
    &#39;%&#39;,
    &#39;^&#39;,
    &#39;5&#39;,
    &#39;Z&#39;,
    &#39;(&#39;,
    &#39;G&#39;,
    &#39;_&#39;,
    &#39;O&#39;,
    &#39;`&#39;,
    &#39;S&#39;,
    &#39;-&#39;,
    &#39;N&#39;,
    &#39;<&#39;,
    &#39;D&#39;,
    &#39;{&#39;,
    &#39;}&#39;,
    &#39;[&#39;,
    &#39;]&#39;,
    &#39;h&#39;,
    &#39;;&#39;,
    &#39;W&#39;,
    &#39;.&#39;,
    &#39;/&#39;,
    &#39;|&#39;,
    &#39;:&#39;,
    &#39;1&#39;,
    &#39;E&#39;,
    &#39;L&#39;,
    &#39;4&#39;,
    &#39;&&#39;,
    &#39;6&#39;,
    &#39;7&#39;,
    &#39;#&#39;,
    &#39;9&#39;,
    &#39;a&#39;,
    &#39;A&#39;,
    &#39;b&#39;,
    &#39;B&#39;,
    &#39;~&#39;,
    &#39;C&#39;,
    &#39;d&#39;,
    &#39;>&#39;,
    &#39;e&#39;,
    &#39;2&#39;,
    &#39;f&#39;,
    &#39;P&#39;,
    &#39;g&#39;,
    &#39;)&#39;,
    &#39;?&#39;,
    &#39;H&#39;,
    &#39;i&#39;,
    &#39;X&#39;,
    &#39;U&#39;,
    &#39;J&#39;,
    &#39;k&#39;,
    &#39;r&#39;,
    &#39;l&#39;,
    &#39;3&#39;,
    &#39;t&#39;,
    &#39;M&#39;,
    &#39;n&#39;,
    &#39;=&#39;,
    &#39;o&#39;,
    &#39;+&#39;,
    &#39;p&#39;,
    &#39;F&#39;,
    &#39;q&#39;,
    &#39;!&#39;,
    &#39;K&#39;,
    &#39;R&#39;,
    &#39;s&#39;,
    &#39;c&#39;,
    &#39;m&#39;,
    &#39;T&#39;,
    &#39;v&#39;,
    &#39;j&#39;,
    &#39;u&#39;,
    &#39;V&#39;,
    &#39;w&#39;,
    &#39;,&#39;,
    &#39;x&#39;,
    &#39;I&#39;,
    &#39;$&#39;,
    &#39;Y&#39;,
    &#39;z&#39;,
    &#39;*&#39;
  );
  # Array indice friendly number of chars;
  $numChars = count($chars) - 1;
  $token = &#39;&#39;;
  # Create random token at the specified length
  for ($i = 0; $i < $len; $i++)
    $token .= $chars[mt_rand(0, $numChars)];
  # Should token be run through md5?
  if ($md5) {
    # Number of 32 char chunks
    $chunks = ceil(strlen($token) / 32);
    $md5token = &#39;&#39;;
    # Run each chunk through md5
    for ($i = 1; $i <= $chunks; $i++)
      $md5token .= md5(substr($token, $i * 32 - 32, 32));
    # Trim the token
    $token = substr($md5token, 0, $len);
  }
  return $token;
}
?>

form.php

<?php
include_once("token.php");
$token = getToken();
session_start();
$_SESSION[&#39;token&#39;] = $token;
?>
<form action="action.php" method="post"
<input type="hidden" name="token" value="<?=$token?>" />
<!-- 其他input submit之类的 -->
</form>

action.php

<?php
session_start();
if($_POST[&#39;token&#39;] == $_SESSION[&#39;token&#39;]){
  unset($_SESSION[&#39;token&#39;]);
  echo "这是一个正常的提交请求";
}else{
  echo "这是一个非法的提交请求";
}
?>

この記事が、PHP プログラミングの皆様のお役に立てれば幸いです。

繰り返し送信を防ぐために PHP フォームにトークンを追加する方法の詳細については、PHP 中国語 Web サイトに注目してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。