web-dev-qa-db-ja.com

確認メール用の推測不可能なトークンの生成

確認メールのリンクをクリックするときに使用するトークンを生成しています。 niqid() を使用する予定ですが、出力は予測可能であるため、攻撃者は確認の電子メールをバイパスできます。私の解決策はそれをハッシュすることです。しかし、それでも十分ではありません。私が使用しているハッシュが見つかった場合でも、それは予測可能だからです。解決策はそれを塩にすることです。関数を使用して可変ソルトを与える場合(たとえば、疑似コードhash(uniqid()+time())の場合)、ハッシュの一意性は保証されないので、方法がわかりません。定数ハッシュを使用すれば十分です(例:hash(uniqid()+asd741)

答えはすべて重要な点を見逃していると思います。一意である必要があります。 openssl_random_pseudo_bytes()が同じ数値を2回生成した場合はどうなりますか?そうすると、1人のユーザーが自分のアカウントをアクティブ化できなくなります。同じ数を2度生成することはまずないという人々の反論はありますか?そのため、出力が一意であるため、uniqid()を検討していました。

私は両方を使用してそれらを一緒に追加できると思います。

13
Celeritas

推測不可能なランダム性が必要です。次に、推測できないランダム性を使用します。ローカルにプラグインする openssl_random_pseudo_bytes() を使用します 暗号的に強力なPRNGRand() または mt_Rand() を使用しないでください。これらは予測可能であるため(mt_Rand() is統計的に良いが、知的な攻撃者に対しては成り立たない)。妥協せず、適切なPRNGを使用してください。 しないでくださいハッシュ関数などをスローして自分で何かを作ろうとする;悲しみだけがこの道の終わりにあります。

16バイトを生成し、文字列が必要な場合は文字列にエンコードします。 bin2hex()は16進数でエンコードします。 16バイトは32文字になります。 base64_encode()はBase64でエンコードします。 16バイトは24文字になります(最後の2つは「=」記号です)。

16バイトは128ビットです。これは「安全な値」であり、衝突を起こす可能性が非常に低いため、衝突を心配する必要はありません。正当な理由がない限り、それ以下にしないでください(それでも、16未満にしないでください)。

25
Tom Leek

OpenSSLサポート があることを確認してください。このワンライナーで問題が発生することはありません。

$token = bin2hex(openssl_random_pseudo_bytes(16));
18
Adi

PHP 7では、 random_bytes

ソルト、キー、または初期化ベクトルを生成するときなど、暗号化の使用に適した暗号化ランダムバイトの任意の長さの文字列を生成します。

したがって、16バイトの16進数トークンを生成するには、次のようにします。

$token = bin2hex(random_bytes(16));

正式には、すべての数値が一意であるという保証はありません。しかし、衝突が発生する可能性は非常に低いため、メーターライトに襲われることを心配する方がよいでしょう。

1
Anders