Webサイトのフォームにセキュリティを追加しようとしています。フォームの1つはAJAXを使用し、もう1つは単純な「お問い合わせ」フォームです。CSRFトークンを追加しようとしています。私が抱えている問題は、トークンが表示されるだけですHTMLの「値」の中にある場合があります。それ以外の場合、値は空です。AJAXフォームで使用しているコードは次のとおりです。
PHP:
if (!isset($_SESSION)) {
session_start();
$_SESSION['formStarted'] = true;
}
if (!isset($_SESSION['token']))
{$token = md5(uniqid(Rand(), TRUE));
$_SESSION['token'] = $token;
}
HTML
<form>
//...
<input type="hidden" name="token" value="<?php echo $token; ?>" />
//...
</form>
助言がありますか?
セキュリティコードについては、次のようにトークンを生成しないでください:$token = md5(uniqid(Rand(), TRUE));
Rand()
は予測可能ですuniqid()
は最大29ビットのエントロピーのみを追加しますmd5()
はエントロピーを追加せず、決定論的に混合しますこれを試してください:
_session_start();
if (empty($_SESSION['token'])) {
$_SESSION['token'] = bin2hex(random_bytes(32));
}
$token = $_SESSION['token'];
_
サイドノート: 私の雇用主のオープンソースプロジェクト の1つは、random_bytes()
およびrandom_int()
をPHP 5プロジェクトにバックポートするイニシアチブです。 MIT Githubでライセンスされており、利用可能です。Composer as paragonie/random_compat 。
_session_start();
if (empty($_SESSION['token'])) {
if (function_exists('mcrypt_create_iv')) {
$_SESSION['token'] = bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM));
} else {
$_SESSION['token'] = bin2hex(openssl_random_pseudo_bytes(32));
}
}
$token = $_SESSION['token'];
_
_==
_または_===
_を使用するだけでなく、 hash_equals()
を使用してください(PHP 5.6+のみですが、 hash-compat library)。
_if (!empty($_POST['token'])) {
if (hash_equals($_SESSION['token'], $_POST['token'])) {
// Proceed to process the form data
} else {
// Log this as a warning and keep an eye on these attempts
}
}
_
hash_hmac()
を使用して、特定のフォームでのみ使用できるようにトークンをさらに制限できます。 HMACは、より弱いハッシュ関数(例:MD5)でも安全に使用できる特定のキー付きハッシュ関数です。ただし、代わりにハッシュ関数のSHA-2ファミリを使用することをお勧めします。
最初に、HMACキーとして使用する2番目のトークンを生成してから、次のようなロジックを使用してレンダリングします。
_<input type="hidden" name="token" value="<?php
echo hash_hmac('sha256', '/my_form.php', $_SESSION['second_token']);
?>" />
_
そして、トークンを検証するときに一致する操作を使用します。
_$calc = hash_hmac('sha256', '/my_form.php', $_SESSION['second_token']);
if (hash_equals($calc, $_POST['token'])) {
// Continue...
}
_
_$_SESSION['second_token']
_を知らないと、1つのフォーム用に生成されたトークンを別のコンテキストで再利用できません。 ページにドロップしたばかりのトークンとは別のトークンをHMACキーとして使用することが重要です。
Twigテンプレートエンジン を使用する人は誰でも、このフィルターをTwig環境に追加することにより、単純化された二重戦略の恩恵を受けることができます。
_$twigEnv->addFunction(
new \Twig_SimpleFunction(
'form_token',
function($lock_to = null) {
if (empty($_SESSION['token'])) {
$_SESSION['token'] = bin2hex(random_bytes(32));
}
if (empty($_SESSION['token2'])) {
$_SESSION['token2'] = random_bytes(32);
}
if (empty($lock_to)) {
return $_SESSION['token'];
}
return hash_hmac('sha256', $lock_to, $_SESSION['token2']);
}
)
);
_
このTwig関数では、両方の汎用トークンを次のように使用できます。
_<input type="hidden" name="token" value="{{ form_token() }}" />
_
または、ロックダウンされたバリアント:
_<input type="hidden" name="token" value="{{ form_token('/my_form.php') }}" />
_
Twigはテンプレートのレンダリングのみに関係しています。トークンを適切に検証する必要があります。私の意見では、Twig戦略は最大限のセキュリティの可能性を維持しながら、より高い柔軟性とシンプルさを提供します。
各CSRFトークンを1回だけ使用できるというセキュリティ要件がある場合、検証が成功するたびに最も単純な戦略でトークンが再生成されます。ただし、そうすると、以前のすべてのトークンが無効になり、複数のタブを一度に閲覧するユーザーとうまく混合できません。
Paragon Initiative Enterprisesは、これらのコーナーケースに対して Anti-CSRFライブラリ を維持しています。これは、1回限りのフォームごとのトークンでのみ機能します。十分なトークンがセッションデータに保存されると(デフォルト構成:65535)、最も古い未使用のトークンが最初にサイクルアウトされます。
セキュリティ警告:
md5(uniqid(Rand(), TRUE))
は、乱数を生成する安全な方法ではありません。詳細については、 この回答 をご覧ください。
Ifでelseが必要なようです。
if (!isset($_SESSION['token'])) {
$token = md5(uniqid(Rand(), TRUE));
$_SESSION['token'] = $token;
$_SESSION['token_time'] = time();
}
else
{
$token = $_SESSION['token'];
}
変数$token
は、セッション中にセッションから取得されていません