- 赤色のリンクは、まだ日本語Codexに存在しないページ・画像です。英語版と併せてご覧ください。(詳細)
データ検証
信頼できないデータが、さまざまな情報源から入ってきます (ユーザー、第三者のサイト、あなた自身のデータベースも!…)。そして、これらすべては、入力時と出力時の両方で検証する必要があります。
目次
出力の無害化
データの無害化 (サニタイズ) をする方法は、データの種類およびそれが使われる文脈 (コンテキスト) に依存します。WordPress における共通の処理と、どのように無害化すべきかを以下に示します。
ヒント : 出力の検証は、可能な限り遅く行うことがよいでしょう。スクリプトでは、出力をする、まさにその時に検証するのが理想です。こうすることで、常にデータが適切に検証/エスケープされていることが確認でき、変数が既に検証されているか覚えておく必要はありません。
整数値
- intval( $int ) または (int) $int
- 整数値を想定するならば、キャストします。
- absint( $int )
- 結果が負でないことを保証します。
HTML/XML
(HTML文書に対して) 多くの形式のXML文書が理解する文字実体参照は '
、&
、>
、<
、"
の5つのみであることに注意してください。テキストを XML 書類として出力するときは、不正な文字実体参照を含むあらゆるテキストを、WordPress の ent2ncr( $text )
関数を通してフィルターしてください。
HTML/XML の断片
- wp_kses( (string) $fragment, (array) $allowed_html, (array) $protocols = null )
- KSES は悪意あるスクリプトを除去します。すべての信頼できない HTML (投稿文、コメント文など) は
wp_kses()
を通すべきです。使い方やデフォルト値などはwp-includes/kses.php
を参照してください。 - 許可する HTML タグの配列を
wp_kses()
に渡す代わりに、wp_kses_post( (string) $fragment )
を用いて投稿やページで許可されるタグを定義したり、wp_kses_data( (string) $fragment )
を用いてコメントで許可されるタグのリストを定義することができます。 -
wp_rel_nofollow( (string) $html )
- あらゆる <a> リンクに "rel='nofollow'" 属性をつけます。
-
wp_kses_allowed_html( (string) $context )
- 所定のコンテキストで許可される HTML タグの配列を提供します。許可されるものは、post | strip | data | entities や pre_user_description のようなフィールドフィルターです。
テキスト節
-
esc_html( $text )
(Version 2.8 以降) - 「< (小ナリ)」、「> (大ナリ)」、「& (アンド)」、「" (ダブルクォーテーション)」、「' (シングルクォーテーション)」 をエンコードします。
esc_attr
と非常に良く似ています。 -
esc_html__
(Version 2.8 以降) - 翻訳、エンコードをします。
-
esc_html_e
(Version 2.8 以降) - 翻訳、エンコード、出力をします。
-
esc_textarea
(Version 3.1 以降) - テキストエリアの要素をエンコードします。
-
sanitize_text_field
(Version 2.9.0 以降) - ユーザーからの入力又はデータベースからの入力を無害化します。
属性値
-
esc_attr( $text )
(Version 2.8 以降) -
esc_attr__()
- 翻訳、エンコードをします。
-
esc_attr_e()
- 翻訳、エンコード、出力wします。
JavaScript
-
esc_js( $text )
(Version 2.8 以降)
URL
-
esc_url( $url, (array) $protocols = null )
(Version 2.8 以降) - URL を無害化するときは、常に
esc_url
を使ってください (テキスト中、属性値、その他あらゆる場所で)。ホワイトリストで提供されたプロトコル(デフォルトは http ならびに https、ftp、ftps、mailto、news、irc、gopher、nntp、feed、telnet)を持たない URL は拒否し、不正な文字を排除し、危険な文字を除去します。3.0 で非推奨とされたclean_url()
の代わりに使います。 - この関数は文字を HTML 実体にエンコードします。(X)HTML あるいは XML 書類を生成するときはこの関数を使ってください。アンド (&) とシングルクォートは (') 数値実体参照 (&, ') にエンコードします。
-
esc_url_raw( $url, (array) $protocols = null )
(Version 2.8 以降) - URL をデータベースに格納するための関数です。この関数は文字を HTML 実体にエンコードしません。URL をエンコードしない形で保存したいときはこの関数を使ってください。 この機能は古い関数
clean_url
関数の$context
をdb
に設定するのと同等です。 -
urlencode( $scalar )
- URL をエンコードします。(例えば、クエリパラメータで使用する、など)
-
urlencode_deep( $array )
- 配列の全要素を URL エンコードします。
データベース
-
$wpdb->insert( $table, (array) $data )
-
$data
は未エスケープとしてください (この関数がエスケープしてくれます)。配列キーがカラム、配列値がデータベース値になります。 -
$wpdb->update( $table, (array) $data, (array) $where )
-
$data
は未エスケープとしてください。配列キーがカラム、配列値がデータベース値になります。$where
は未エスケープとしてください。複数のWHERE
節はAND
で連結されます。
$wpdb->update( 'my_table', array( 'status' => $untrusted_status, 'title' => $untrusted_title ), array( 'id' => 123 ) );
-
$wpdb->prepare( $format, (scalar) $value1, (scalar) $value2, ... )
-
$format
は sprintf() 形式に似た文字列です。%s
と%d
のみ理解します。どちらもクォート文字で囲む必要はありません。
$wpdb->get_var( $wpdb->prepare( "SELECT something FROM table WHERE foo = %s and status = %d", $name, // 未エスケープの文字列 (関数が無害化します) $status // 信頼できない整数値 (関数が無害化します) ) );
-
esc_sql( $sql )
-
$wpdb->escape()
のエイリアス。 -
$wpdb->escape( $text )
- 3.6から非推奨になりました。
esc_sql()
または$wpdb->prepare()
を代わりに使ってください。 -
$wpdb->escape_by_ref( &$text )
- 返り値はありません。パラメータが参照で渡されるので、テキストが直接変更され、返り値を割り当てる必要がありません。
-
like_escape( $string )
- SQL クエリの LIKE 式用に
$string
を無害化します。さらに SQL エスケープする必要があります (上記のいずれかの関数を使う)。
ファイルシステム
-
validate_file( (string) $filename, (array) $allowed_files = "" )
- ディレクトリートラバーサル攻撃を防止する、あるいはファイル名がホワイトリストにあるか確認します。
$filename
が正答な相対パスならば 0 を返します。検証後、$filename
を相対パスとして扱わなければなりません (MUST) (例えば、ABSPATH の後に繋げる等)。なぜなら、/etc/hosts
はこの関数で正当と判定されるからです。返り値が正の整数の場合は、.., ./, あるいは : がパスに含まれているか、または$allowed_files
ホワイトリストに含まれていません。この結果を真偽判定する場合は注意してください。false (0) はファイル名が検証を通過したことを示し、true (> 0) は検証されなかったことを示します。
HTTP ヘッダ
ヘッダ分割攻撃は、HTTP クライアントに依存するため、やっかいなものです。 WordPress は、HTTP ヘッダにユーザーが生成した内容を含む必要はほとんどありませんが、それを行うならば、WordPress は HTTP ヘッダの多くにホワイトリストを用います。
WordPress は、HTTP のロケーションヘッダにユーザーが生成した内容を使えますが、以下のように無害化できます。
-
wp_redirect($location, $status = 302)
- あらゆる URL に対する安全なリダイレクト方法です。結果の HTTP ロケーションヘッダが妥当であることを保証します。
-
wp_safe_redirect($location, $status = 302)
- さらに安全です。ホワイトリストにあるドメインしかリダイレクトしません。
入力の検証
出力の無害化に挙げられた多くの関数は、入力の検証にも使えます。 さらに、WordPress は以下の関数を使っています。
スラッグ
-
sanitize_title( $title )
- 投稿スラッグなどに使われています。
-
sanitize_user( $username, $strict = false )
- 新規ユーザーを作成するときは
$strict
を使ってください (API でユーザー追加するとき)。
HTML
-
balanceTags( $html )
orforce_balance_tags( $html )
- 正当な XML 出力になるよう、HTML タグの開き/閉じの釣り合いを取ります。
-
tag_escape( $html_tag_name )
- HTML タグ名を無害化します (関数名と違って、エスケープは何もしません)。
-
sanitize_html_class( $class, $fallback )
- HTML クラス名を無害化し、妥当な文字列のみを含むことを保証します。A-Z,a-z,0-9,'-' に限定します。結果が空文字列になる場合は、第二引数で与えられた代替文字列を返します。
-
is_email( $email_address )
- 妥当でない場合は false を返し、妥当な場合は $email_address を返します。
配列
-
array_map( 'absint', $array )
- 配列要素がすべて非負であることを保証します。あなたのデータに合うようにコールバック関数 'absint' を入れ替えてください。array_map() は PHP コアの関数で、配列の要素に任意のコールバック関数を実行します。この例ではコールバック関数は absint() です。
その他
その他の、データの無害化に役立つ関数です。
- sanitize_email()
- sanitize_file_name()
- sanitize_html_class()
- sanitize_key()
- sanitize_mime_type()
- sanitize_option()
- sanitize_sql_orderby()
- sanitize_text_field()
- sanitize_title_for_query()
- sanitize_title_with_dashes()
- sanitize_user()
- sanitize_meta()
- sanitize_term()
- sanitize_term_field()
検証の哲学
検証をどのように行うか、いくつか異なった哲学があります。どれが正しいかは筋書によって異なります。
ホワイトリスト
既知および信頼された値の一覧にあるデータのみ受理します。
$possible_values = array( 'a', 1, 'good' ); if ( !in_array( $untrusted, $possible_values ) ) die( "やっちゃダメ!" );
// Be careful here with fancy breaks and default actions. switch ( $untrusted ) { case 'a' : ... break; ... default : die( "ろくでなし!" ); }
ブラックリスト
既知の信頼できない値の一覧にあるデータを拒否します。これがよい方法であることは、めったにありません。
書式の検出
データが正しい書式であるかテストします。正しい場合のみ受理します。
if ( !ctype_alnum( $data ) ) die( "あなたのデータは※△□%&〒☆" ); if ( preg_match( "/[^0-9.-]/", $data ) ) die( "浮動小数じゃない? おバカ!" );
書式の訂正
ほとんどのデータを受理し、危険な部分を除去または変更します。
$trusted_integer = (int) $untrusted_integer; $trusted_alpha = preg_replace( '/[^a-z]/i', "", $untrusted_alpha ); $trusted_slug = sanitize_title( $untrusted_slug );
変更履歴
- 3.6:
$wpdb->escape()
の代わりにesc_sql()
と$wpdb->preapre()
が推奨となりました。 - 3.1:
esc_textarea
が導入されました。 (#15454) - 3.0:
clean_url()
の代わりにesc_url()
とesc_url_raw()
が推奨となりました。 (#12309) - 2.8: 以下の関数が非推奨となりました。(via WordPress Development Updates)
-
sanitize_url()
->esc_url_raw()
-
wp_specialchars()
->esc_html()
(also:esc_html__()
andesc_html_e()
) -
attribute_escape()
->esc_attr()
(also:esc_attr__()
andesc_attr_e()
)
-
外部資料
- Data Sanitization and Validation With WordPress by Stephen Harris
- Theme and Plugin Security by Mark Jaquith
- wp_specialchars() vs attribute_escape() ( now esc_attr() ) and quote entity-encoding.
最新英語版: WordPress Codex » Data Validation (最新版との差分)