ホームページ  >  記事  >  バックエンド開発  >  PHP フォームは繰り返し送信を防止します (CSRF 対策の脆弱性)

PHP フォームは繰り返し送信を防止します (CSRF 対策の脆弱性)

不言
不言オリジナル
2018-04-20 11:44:013743ブラウズ

この記事の内容は、PHP フォームの繰り返し送信の防止 (CSRF 脆弱性の防止) に関するものです。必要な友人に参考にしていただけるように共有します。

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

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

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

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

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

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

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

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

1. 最初に xss 攻撃を阻止します

2. リファラーを検証します

3. トークンなどの重要な Cookie 設定 https のみ 4. 署名、トークンを使用します

5.get は情報のクエリにのみ使用されます

6. post を使用してフォームを送信します

7. クロススクリプトインジェクションは注意して使用してください


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


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

<span style="margin:0px;padding:0px;"></span>その原理は、フォームを送信した後、この文字列が検証されることにより、重複した送信を防ぐことができます。他の人はフォームを自分で作成して送信を不正に行うことはできません。または、ダブルクリックして送信します。

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>

<span style="margin:0px;padding:0px;"></span><span style="margin:0px;padding:0px;"></span>

上面的比较简单一点的方法,下面的代码更加安全一点。

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;
}
?>

<span style="margin:0px;padding:0px;"></span>

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>

<span style="margin:0px;padding:0px;"></span>

action.php


Token.php🎜🎜🎜🎜🎜🎜🎜🎜rrreee🎜<span style="margin:0px;padding:0px;"></span>🎜🎜🎜🎜🎜🎜

form.php🎜🎜🎜🎜🎜🎜🎜🎜rrreee🎜<span style="margin:0px;padding:0px;"></span>🎜🎜🎜🎜🎜🎜

action.php🎜🎜🎜


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

<span style="margin:0px;padding:0px;"></span>

🎜🎜🎜🎜🎜🎜rrreee🎜<span style="margin:0px;padding:0px ;"></span>🎜🎜🎜🎜🎜🎜関連する推奨事項:

変数で表されるPHPフォーム名の値の問題

PHPフォームファイルのiframe非同期アップロード例の詳細な説明



以上がPHP フォームは繰り返し送信を防止します (CSRF 対策の脆弱性)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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