PHP7初級試験 模擬問題 – 出題範囲: ユーザとの情報交換:Webフォームの作成 からの出題となります。
受験を考えているあなたも、試験を合格したあなたも、ぜひチャレンジしてみてください!
問題
次の選択肢のなかで、正しいものはどれでしょう? (1つ選択)
- フォームでユーザーが入力した HTML タグをそのまま受け入れる場合、使用できないタグを指定して取り除く必要がある
- サーバ変数
$_SERVER['PHP_NAME']
には Web サーバーに要求する URL のパス名が格納されている - フォームで同じ名前に複数の値を入れる場合
name="sample[]"
のように記載すると、サーバ側では$_POST['sample']
にカンマ区切りで複数値が取得できる - 値が
null
を含んでいる可能性のある変数を判定するのに Null 合体演算子??
を使用するとよい $test
が整数であるかを検証する場合はfilter_var($test, FILTER_SANITIZE_NUMBER_INT)
を使用するとよい
解答と解説は下にスクロールしてください
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
解答
正解は 4. です。
解説
1. フォームでユーザーが入力した HTML タグをそのまま受け入れる場合、使用できないタグを指定して取り除く必要がある
使用できないタグを指定するのではなく、使用できるタグを指定します。
使用できないタグを指定する方法を、一般的にブラックリスト方式と呼ぶこともあります。
ブラックリスト方式の特徴は、原則はすべて許可しますが一部のみ排除する考え方にあたります。
ブラックリスト方式ですと、規格やブラウザ側で新しいタグが制定されるたびに対応しなくてはならないことや、一部ブラウザが過去の非推奨のタグを認識してしまうなどの恐れがあります。
一方で、使用できるタグを指定する方法を、一般的にホワイトリスト方式と呼ぶこともあります。
ホワイトリスト方式の特徴は、原則はすべて排除しますが一部のみ許可する考え方にあたります。
ホワイトリスト方式を採用すると、例えば文字を一部分のみ太字にするなど、意図したタグのみ許可することで必要な機能を利用できつつ、想定していない機能はすべて排除することができます。
【試験合格後もステップアップ!】
HTMLタグの指定を許可する際には、属性の許可についても注意が必要です。
その中でも特に、style
属性には注意が必要です。
最近はCSSで使用できる機能が増えたことにより、CSSを利用しての攻撃も確認されています。
プログラムを作成する際にはホワイトリスト方式を意識して、すべての入力値を疑うゼロトラストの考え方をきちんと押さえてください。
このときの入力値には、自分が作成した値も疑われる対象に含むべきです。
最近は、HTML タグではなく MarkDown 表記を許可する方法などの方法もあります。
2. サーバ変数 $_SERVER['PHP_NAME']
には Web サーバーに要求する URL のパス名が格納されている
$_SERVER['PHP_NAME']
は存在しません。 選択肢の内容にあたるものは $_SERVER['PHP_SELF']
です。
他に使用できるキー名の一部として、下記のようなものがあります。
$_SERVER[’SERVER_NAME’]
: 現在のスクリプトが実行されているサーバーのホスト名$_SERVER[’SERVER_ADDR’]
: 現在のスクリプトが実行されているサーバーの IP アドレス$_SERVER[’SCRIPT_NAME’]
: 現在のスクリプトのパス$_SERVER[’REMOTE_HOST’]
: 現在のページにアクセスしているホスト名$_SERVER[’REMOTE_ADDR’]
: 現在ページをみているユーザーの IP アドレス
その他に使用できるキー名は、公式ページをご参照ください。
PHPマニュアル – 定義済の変数 $_SERVER
https://www.php.net/manual/ja/reserved.variables.server.php
【試験合格後もステップアップ!】$_SERVER['PHP_SELF']
と $_SERVER[’SCRIPT_NAME’]
は似たような値を取得できます。
基本的には $_SERVER[’SCRIPT_NAME’]
を推奨します。
では何が違うのでしょうか?
例として https://example.com/test.php/ のアドレスでスクリプト内でそれぞれ値を取得した場合、下記のような違いがあります。
・ $_SERVER['PHP_SELF']
: https://example.com/test.php/
・ $_SERVER[’SCRIPT_NAME’]
: https://example.com/test.php
ほとんどのケースにおいて基本的にスクリプトのパスを取得したいことであるため、想定以外の値が格納されている可能性のある $_SERVER['PHP_SELF']
は推奨されていません。
想定値以外が格納される可能性がある場合は、脆弱性が生まれ攻撃される可能性があるということと同義であるためです。
3. フォームで同じ名前に複数の値を入れる場合 name="sample[]"
のように記載すると、サーバ側では $_POST['sample']
にカンマ区切りで複数値が取得できる
サーバ側では $_POST['sample']
にカンマ区切りではなく、配列により複数値が取得できます。
例えば sample
という名前に対し3つの値をフォームから送信されている場合は、$_POST['sample'][0]
、 $_POST['sample'][1]
、$_POST['sample'][2]
のように指定すればそれぞれ取得できます。
実際の複数値の取得や処理は foreach
などを使用して取得することが一般的です。
【試験合格後もステップアップ!】$_POST
と同じくフォームの値を取得できるスーパーグローバル変数として $_REQUEST
がありますが、原則使わないようにしてください。$_GET
で取得したい値、 $_POST
で取得したい値は指定して取得すべきです。
また、 $_GET
、$_POST
と $_COOKIE
で同じ名前のものがあった場合に上書きされ取得される可能性もあります。
4. 値が null
を含んでいる可能性のある変数を判定するのに Null 合体演算子 ??
を使用するとよい
選択肢のとおりです。
PHP 7.0 で Null 合体演算子が導入されました。
変数の値が null
の場合に初期値を設定したい場合に、簡単に表記できるようになりました。
$test
が null
でない場合に $test
を返し、 $test
が null
の場合は初期値を返したい場合では下記のように表記できます。
echo $test ?? 'null です';
PHP 7 より前のバージョンでは主に下記のように表記していました。
echo isset( $test ) ? $test : 'null です';
このような表記ではどうしても変数名を2回書いてしまうことになり、表記としては冗長になりがちでした。
【試験合格後もステップアップ!】
PHP 7 以降では Null に関連する機能が追加されています。
PHP 7.1 新機能 : Nullable 型 ?<型>
パラメータや返り値の型宣言で、指定した型だけでなく null
も許容することができます。 function test( ?string param ): ?string
https://www.php.net/manual/ja/migration71.new-features.php
PHP 7.4 新機能 : Null 合体代入演算子 ??=
変数が null
だった場合のみ値を代入できます。$test = $test ?? ‘null です';
を $test ??= 'null です';
と短く表記できます。 https://www.php.net/manual/ja/migration74.new-features.php
PHP 8.0 新機能 : Nullsafe 演算子 ?->
呼び出しチェインを行う ->
演算子で if
文を使うことなく null
のチェックができるようになります。 https://www.php.net/releases/8.0/ja.php
また、Null 合体演算子に似た記号にエルビス演算子 ?:
があります。
こちらは三項演算子の特別な書き方で、 true
の場合はもとの値を、 false
の場合は指定した値を返します。echo $test ?: ‘false です’;
ただし、エルビス演算子はあまり使われない表記であるため、他の開発者がコードを確認する際に読みにくくなるかもしれません。
エルビス演算子は使用せず三項演算子で表記することを、コーディング規約でルール化することをおすすめします。
5. $test が整数であるかを検証する場合は filter_var($test, FILTER_SANITIZE_NUMBER_INT) を使用するとよい
FILTER_SANITIZE_NUMBER_INT
は除去フィルタです。FILTER_VALIDATE_INT
が検証フィルタになります。
検証フィルタはバリデーションともいいます。
入力された値が、想定されている範囲のものかを確認するものです。
ここで言う範囲とは、型だけではなく最小値や最大値の範囲内である意味も含みます。
例えば、FILTER_VALIDATE_INT
では、値が整数であるかどうか、オプション min_range
と max_range
で指定した範囲内にあるかどうかを検証し、成功した場合は整数に変換します。
検証フィルタについては下記の公式ドキュメントを参照してください。 https://www.php.net/manual/ja/filter.filters.validate.php
他にも strlen()
関数や正規表現などを使い、入力された値が想定された範囲内であるか確認する方法も用いられます。
一方で、除去フィルタはサニタイジングともいいます。
こちらは入力された文字を無害化させるために用いられます。
例えば、FILTER_SANITIZE_NUMBER_INT
では、数字、プラス記号、マイナス記号以外のすべての文字を取り除きます。
除去フィルタについては下記の公式ドキュメントを参照してください。 https://www.php.net/manual/ja/filter.filters.sanitize.php
trim()
関数で不要な空白を除去することもよく用いられます。
【試験合格後もステップアップ!】
セキュリティで重要な項目の一つに、入力された値の検証や除去があげられます。
これは関数レベルでも考慮すべき項目です。たとえプライベートな自作の関数で、自分しか使わないと思っていても、引数の値を型や範囲をまず確認することが重要です。
上記で紹介している検証フィルタや除去フィルタは最低限のものになります。 例えばディレクトリやパスを受け取る前提であれば、パスを文字列として検証した後に、ディレクトリトラバーサルの考慮を含めた検証をする必要があります。
試験の情報
今回の内容は、セキュリティや脆弱性に直結するものなのできちんと押さえておいてください。
PHP 7 初級レベルではウェブ・セキュリティの基本を押さえただけにとどまりますので、実務ではもう少し深く知っておく必要があります。
ウェブ・セキュリティの名著として知られる徳丸浩氏による「体系的に学ぶ 安全なWebアプリケーションの作り方 第2版」では、より丁寧で詳細にウェブ・セキュリティについて学ぶことができますのでおすすめです。
上記の本は「ウェブ・セキュリティ基礎試験(通称:徳丸基礎試験)」の主教材でもあります。
徳丸基礎試験は Python や Ruby on Rails などの PHP 以外の言語で Web アプリケーションを作成されている方にも非常に有益な試験となっております。
知識としても実務としても PHP 関わらず幅広く使えるため、ウェブに関わるエンジニアに私が一番オススメしている試験が「徳丸基礎試験」だったりします。
PHP 7 初級を合格した方は、徳丸基礎試験もぜひチャレンジしてみてください!