検証の哲学

検証がどのように行われるべきかについて、いくつかの異なる哲学があります。それぞれは異なるシナリオに適しています。

セーフリスト

既知の信頼できる値の有限リストからのみデータを受け入れます。

信頼できないデータをセーフリストと比較する際には、厳密な型チェックを使用することが重要です。そうしないと、攻撃者がセーフリストを通過するように入力を作成し、依然として悪意のある影響を及ぼす可能性があります。

比較演算子

  1. $untrusted_input = '1 malicious string'; // will evaluate to integer 1 during loose comparisons
  2. if ( 1 === $untrusted_input ) { // == would have evaluated to true, but === evaluates to false
  3. echo '<p>Valid data';
  4. } else {
  5. wp_die( 'Invalid data' );
  6. }

in_array()

  1. $untrusted_input = '1 malicious string'; // will evaluate to integer 1 during loose comparisons
  2. $safe_values = array( 1, 5, 7 );
  3. if ( in_array( $untrusted_input, $safe_values, true ) ) { // `true` enables strict type checking
  4. echo '<p>Valid data';
  5. } else {
  6. wp_die( 'Invalid data' );
  7. }

switch()

  1. $untrusted_input = '1 malicious string'; // will evaluate to integer 1 during loose comparisons
  2. switch ( true ) {
  3. case 1 === $untrusted_input: // do your own strict comparison instead of relying on switch()'s loose comparison
  4. echo '<p>Valid data';
  5. break;
  6. default:
  7. wp_die( 'Invalid data' );
  8. }

ブロックリスト

既知の信頼できない値の有限リストからデータを拒否します。これは非常に稀に良いアイデアです。

フォーマット検出

データが正しいフォーマットであるかどうかをテストします。正しい場合のみ受け入れます。

  1. if ( ! ctype_alnum( $data ) ) {
  2. wp_die( "Invalid format" );
  3. }
  4. if ( preg_match( "/[^0-9.-]/", $data ) ) {
  5. wp_die( "Invalid format" );
  6. }

フォーマット修正

ほとんどのデータを受け入れますが、危険な部分を削除または変更します。

  1. $trusted_integer = (int) $untrusted_integer;
  2. $trusted_alpha = preg_replace( '/[^a-z]/i', "", $untrusted_alpha );
  3. $trusted_slug = sanitize_title( $untrusted_slug );

例1

アメリカの郵便番号を受け入れるように設計された入力フィールドがあるとしましょう:

  1. <input type="text" id="wporg_zip_code" name="my-zipcode" maxlength="10" />

ここでは、ブラウザに最大10文字の入力のみを許可するように指示していますが、どの文字を入力できるかには制限がありません。11221eval()を入力することができます。

ここで検証が必要になります。フォームを処理する際に、各フィールドの適切なデータ型を確認するコードを書き、間違っている場合は破棄します。

例えば:my-zipcodeフィールドをチェックするために、次のようなことを行うかもしれません:

  1. /**
  2. * Validate a US zip code.
  3. *
  4. * @param string $zip_code RAW zip code to check.
  5. *
  6. * @return bool true if valid, false otherwise.
  7. */
  8. function wporg_is_valid_us_zip_code( string $zip_code ):bool {
  9. // Scenario 1: empty.
  10. if ( empty( $zip_code ) ) {
  11. return false;
  12. }
  13. // Scenario 2: more than 10 characters.
  14. // The `maxlength` attribute is only enforced by
  15. // the browser, so we still need to validate the
  16. // length of the input on the server to protect
  17. // against a manual submission.
  18. if ( 10 < strlen( trim( $zip_code ) ) ) {
  19. return false;
  20. }
  21. // Scenario 3: incorrect format.
  22. if ( ! preg_match( '/^d{5}(-?d{4})?$/', $zip_code ) ) {
  23. return false;
  24. }
  25. // Passed successfully.
  26. return true;
  27. }

次に、フォームを処理する際に、あなたのコードはwporg_zip_codeフィールドをチェックし、結果に基づいてアクションを実行する必要があります:

  1. if ( isset( $_POST['wporg_zip_code'] ) && wporg_is_valid_us_zip_code( $_POST['wporg_zip_code'] ) ) {
  2. // $_POST['wporg_zip_code'] is valid; carry on
  3. }

この特定の例は、提供されたデータが正しいフォーマットであることを確認しています。提供されたデータが正しくフォーマットされていても、有効な郵便番号であるかどうかは確認していません。それには、有効な郵便番号のリストと比較するための2番目の関数が必要です。

例2

あなたのコードがデータベースから投稿をクエリし、ユーザーにクエリ結果をソートさせたいとしましょう。

  1. $allowed_keys = array( 'author', 'post_author', 'date', 'post_date' );
  2. $orderby = sanitize_key( $_POST['orderby'] );
  3. if ( in_array( $orderby, $allowed_keys, true ) ) {
  4. // $orderby is valid; carry on
  5. }

この例のコードは、受信したソートキー(orderby入力パラメータに保存)を有効性のために許可されたソートキーの配列と比較してチェックします。これにより、ユーザーが任意の潜在的に悪意のあるデータを渡すことを防ぎます。

受信したソートキーを配列と比較する前に、キーは組み込みのWordPress関数sanitize_key()に渡されます。この関数は(他のことの中で)キーが小文字であることを保証します。これは、in_array()が大文字と小文字を区別する検索を行うため、望ましいです。

truein_array()の第3パラメータに渡すことで、厳密な型チェックが有効になり、関数に値だけでなく値の型も比較するように指示します。これにより、受信したソートキーが文字列であり、他のデータ型ではないことが確実になります。

検証関数

ほとんどの検証はカスタムコードの一部として行われますが、いくつかのヘルパー関数もあります。これらは、サニタイズページにリストされているものに加えてあります。

  • balanceTags( $html )またはforce_balance_tags( $html ) – HTMLタグがバランスが取れていることを確認し、有効なXMLが出力されるようにします。
  • count()は配列内のアイテム数をチェックします。
  • in_array()は配列内に何かが存在するかどうかをチェックします。
  • is_email()はメールアドレスが有効かどうかを検証します。
  • is_array()は何かが配列であるかどうかをチェックします。
  • mb_strlen()またはstrlen()は文字列が期待される文字数を持っているかどうかをチェックします。
  • preg_match()strpos()は他の文字列内の特定の文字列の出現をチェックします。
  • sanitize_html_class( $class, $fallback ) – HTMLクラス名をサニタイズし、有効な文字のみを含むことを保証します。文字列をA-Z、a-z、0-9、’-‘に制限し、これが空の文字列になると、提供された代替値を返します。
  • tag_escape( $html_tag_name ) – HTMLタグ名をサニタイズします(関数の名前にもかかわらず、何もエスケープしません)。
  • term_exists()はタグ、カテゴリ、または他のタクソノミー用語が存在するかどうかをチェックします。
  • username_exists()はユーザー名が存在するかどうかをチェックします。
  • validate_file()は入力されたファイルパスが実際のパスであることを検証します(ただし、ファイルが存在するかどうかは確認しません)。

これらのような他の関数については、WordPressコードリファレンスを確認してください。*_exists()*_validate()is_*()のような名前の関数を検索してください。これらのすべてが検証関数ではありませんが、多くは役立ちます。