
PHP8 上級/準上級試験の認定模擬問題として、プライム・ストラテジー様のPRIME STUDYが認定されているようです。ただ、この模擬問題には解説がありませんので解説をまとめていこうと思います。シリーズ第19回目です。

PHP初級レベルから脱却して中級/上級レベルにいきたい人にピッタリの内容ですね。

今回は推測困難なトークンの生成に関する問題です。特に、CSRF対策などで使用されるセキュリティトークンの生成方法について、暗号論的に安全な関数とそうでない関数の違いを理解することが求められます。しっかり押さえておきましょう!
PRIME STUDY認定模擬問題のリンクはこちらです → https://study.prime-strategy.co.jp/
問題文
推測困難なトークン に関する説明の中で、誤っているものを1つ選びなさい。
また、すべてのコードには下記のコードが適切な箇所に書かれているものとする。
declare(strict_types=1);
error_reporting(-1);
下記はマニュアルから一部引用した内容である。
uniqid ( string $prefix = “” , bool $more_entropy = false ) : string
警告:この関数が生成する値は、暗号学的に安全ではありません。そのため、これを暗号として使ってはいけません。暗号学的に安全な値が必要な場合は、random_int() か random_bytes() あるいは openssl_random_pseudo_bytes() を使いましょう。
mt_rand ( ) : int
mt_rand ( int $min , int $max ) : int
警告:この関数が生成する値は、暗号学的に安全ではありません。そのため、これを暗号として使ってはいけません。暗号学的に安全な値が必要な場合は、random_int() か random_bytes() あるいは openssl_random_pseudo_bytes() を使いましょう。
mt_rand ( ) : int
mt_rand ( int $min , int $max ) : int
警告:この関数が生成する値は、暗号学的に安全ではありません。そのため、これを暗号として使ってはいけません。暗号学的に安全な値が必要な場合は、random_int() か random_bytes() あるいは openssl_random_pseudo_bytes() を使いましょう。
(1)
CSRF 等でも使われる事がある、秘密情報としての「推測(予測)困難なトークン」を作る場合において、random_bytes() は「暗号論的に安全な、疑似ランダムなバイト列を生成する」事が出来る。
そのため、以下のコード
var_dump( bin2hex( random_bytes(24) ) );
は正しく実行でき、結果は
string(48) "e5c471cbf4502eb90dbfbd2480f06a2d6af69ce4b0722b31"
となる (乱数の値は実行毎に変わる)。この値は「暗号論的にランダムなバイト列 (の 16 進表現)」なので、長さが十分であれば「推測 (予測) 困難なトークン」となり得る。
(2)
CSRF 等でも使われる事がある、秘密情報としての「推測(予測)困難なトークン」を作る場合において、openssl_random_pseudo_bytes() は「疑似ランダムなバイト文字列を生成する」事が出来る。
古いシステムでない限り暗号学的に強いアルゴリズムを使って疑似乱数が生成される事が多いが、古いシステムなどでは「暗号学的に強くない」文字列である可能性もあり、それは第二引数によって知る事が出来る。
そのため、以下のコード
var_dump( base64_encode( openssl_random_pseudo_bytes(24, $flg) ) );
var_dump($flg);
は正しく実行でき、結果は
string(32) "OFUw6O7WR785Kg5YZbGZOKDwJzXRn60J"
bool(true)
となる (乱数の値は実行毎に変わる)。この値は、第二引数で与えた $flg の値が true であるため「暗号論的にランダムなバイト列 (の 16 進表現)」なので、長さが十分であれば「推測 (予測) 困難なトークン」となり得る。
(3)
CSRF等でも使われる事がある、秘密情報としての「推測(予測)困難なトークン」を作る場合において。
そのため、以下のコード
var_dump( uniqid((string)mt_rand(), true) );
は正しく実行でき、結果は
string(33) "17821489405e874a50df8b89.86544478"
となる (乱数の値は実行毎に変わる)。uniqid() 関数と mt_rand() 関数を組み合わせているため、この値は「暗号論的にランダムな文字列」なので「推測 (予測) 困難なトークン」となり得る。
(4)
CSRF 等でも使われる事がある、秘密情報としての「推測(予測)困難なトークン」を作る場合において、mt_rand() は乱数を生成するが、
とあるため、これを使用しても推測(予測)困難なトークンを作成する事は出来ない。
そのため、以下のコード
var_dump( mt_getrandmax() );
var_dump( mt_rand() );
は正しく実行でき、結果は
int(2147483647)
int(248780506)
となるが (乱数の値は実行毎に変わる)、この値は「暗号論的にランダムな文字列」ではないので「推測 (予測) 困難なトークン」となり得ない。
解説
選択肢1の解説
正しいです。
random_bytes() は暗号論的に安全な乱数を生成するため、推測困難なトークンとして使用することができます。
選択肢2の解説
正しいです。
openssl_random_pseudo_bytes() も暗号論的に強い疑似乱数を生成することができ、引数で「暗号学的に強くない」かどうかを判定できます。
選択肢3の解説
誤りです。
uniqid() と mt_rand() を組み合わせた値は暗号学的に安全ではなく、推測困難なトークンとしては不適切です。
選択肢4の解説
正しいです。
mt_rand() は暗号学的に安全ではないため、推測困難なトークンを生成するためには使用できません。
正解選択肢
以上より選択肢3が正解となります。
他の問題へ
模擬問題(1)インストール
模擬問題(2)変数の型
模擬問題(3)クラス
模擬問題(4)メソッドその1
模擬問題(5)メソッドその2
模擬問題(6)リファレンス
模擬問題(7)名前空間
模擬問題(8)エラー
模擬問題(9)定義済みのインターフェイスとクラスおよび SPL インターフェイス
模擬問題(10)SPL
模擬問題(11)定義済の変数
模擬問題(12)PHP7.0.xからPHP7.1.xへの移行
模擬問題(13)可変変数
模擬問題(14)PHP7.3.xからPHP7.4.xへの移行
模擬問題(15)PHP7.4.xからPHP8.0.xへの移行
模擬問題(16)制御構造
模擬問題(17)XSS(クロスサイトスクリプティング)
模擬問題(18)ファイルアップロード
模擬問題(19)推測困難なトークン
模擬問題(20)セッション
模擬問題(21)PHP のメモリ消費
模擬問題(22)関数その1
模擬問題(23)関数その2
模擬問題(24)関数その3
模擬問題(25)関数その4
模擬問題(26)関数その5
模擬問題(27)関数その6
模擬問題(28)関数その7
模擬問題(29)関数その8
模擬問題(30)関数その9
コメント