投稿日:2015年9月19日23080セキュリティへの配慮が欠かせないデータベースとのやり取り「WordPressプラグインの解説」第3弾。WordPressのプラグインでは独自のテーブルを作成して利用することもできます。なればWordPressの仕様に縛られること無く、自由なプラグインの開発が可能になります。自由には責任が付きもので、セキュリティに配慮した設計が重要になります。このページではデータベースの基本的な使い方と、必要になるセキュリティ対策について解説をします。本当に独自のテーブルが必要か考えるプラグイン専用テーブルの作成テーブルのバージョンアップ処理テーブルの削除処理データベースへ安全にデータを保存する方法データベースへ保存したデータを取得する方法データベースから取得したデータのエスケープ本当に独自のテーブルが必要か考えるプラグイン独自のデータをデータベースに保存する方法は、新規のテーブルを追加するだけではありません。何でもかんでも新規のテーブルを作るのではなく、WordPressで予め用意されたテーブルが利用できないか調べてみましょう。options他にもWordPressは拡張性の優れた仕組みが用意されており、カスタム投稿タイプやカスタムフィールド、カスタム分類などで代用できないかも検証してみてください。した既存の仕組みでは対応できない場合にだけ、独自のテーブルを追加します。プラグイン専用テーブルの作成WordPressの作法で、データベースを扱う際にはwpdbクラスを呼び出します。テーブルの作り方はテンプレートのようなところがあるので、このように書くもんだと覚えると楽です。Codexの「プラグインでデータベーステーブルを作る」で詳しく解説されているので合わせて参照してください。今回の例は私の自作プラグインでテーブルを作成した時の例です。照合順序を指定する(ある場合。$wpdbでwpdbクラスのグローバルオブジェクトを呼び出します。接頭辞やcharset、照合順序などはWordPressで既に設定されているものを取得します。接頭辞などはサイトによって設定が異なるので、自分サイトがそうだからといって「wp1_」等と指定しないようにしてください。oxy_tableという名前のテーブルを作成しています。後は取得した情報を変数で渡しつつ、SQL文でテーブルを作成するだけです。require_onceでupgrade.phpを呼び出して、dbDeltaにクエリを渡してます。dbDeltaはWordPressで用意されたテーブルを作成・更新するための関数で、必要に応じてテーブルを更新したり、変更したりと柔軟に対応してくれます。フィールド名にアポストロフィを使わないなど、記述方法に癖があるので上のCodexの解説を確認しておいてください。テーブルのバージョンアップ処理プラグインのバージョンアップでテーブルの構成が変更になるのはよくあることです。テーブルのバージョンを設定しておき、構成が変更になった時にバージョンを上げてアップデート処理をします。照合順序を指定する(ある場合。);}変更したのは2行目と、39行目です。2行目でテーブルアップデート用のバージョンを指定しています。optionsテーブルにデータベースのバージョンを保存しています。アップデート時の処理アップデート時にはバージョンを増やし、以下のようにします。このようにしておけば、プラグインのバージョンとデータベースのバージョンがひも付けされるので、アップデートはもちろん、ダウングレードした際にもデータベースを更新することができます。バージョンが異なる場合にアップデート用の処理}}テーブルの削除処理プラグイン有効時にテーブルを作成したら、停止時に削除する処理も必要です。しないと利用者のデータベースに無駄なテーブルを残すことになります。ログ等を残したいプラグインもあると思いますが、そのような実装は多くの場合ありがた迷惑です。(最低でも停止時にログを残すか確認を取るべきです。)前回の投稿で解説したregister_deactivation_hook()のコールバック関数で以下のようにしておきましょう。);}その他、追加したデータベースのバージョンなどの設定も削除するのを忘れないようにしてください。データベースへ安全にデータを保存する方法データベースへの書き込みはプラグインの中でも一番気を使うところです。SQLインジェクション関連の脆弱性報告は毎日のようにされています。攻撃されるのもプラグインを介したSQLインジェクションだそうです。対策は星の数ほどありますが、WordPressではプレースホルダーを利用するのが最も安全です。プレースホルダーは別名プリペアドステートメント、もしくは静的ホルダーとも呼ばれる対策です。SQLインジェクションの危険性について全く理解していないという方は、IPAで配布されている「安全なウェブサイトの作り方」を一読しておくことを強くお勧めします。インジェクション攻撃からクエリを保護する」という解説がありますが少しわかりにくいので実例で見ていきます。※2017/10/05追記:プレースホルダの仕様が変更になったようです。以下の位置指定子は使えなくなったようです。対策としてプレースホルダの数だけ引数を追加してください。※2017/10/20追記:以下の位置指定子を利用した脆弱性が発見されました。詳しい解説は避けますが、以下の補足でも指摘した文字列のシングルクォートの扱いに関する不備です。そのため位置指定子を利用している場合、速やかに利用を停止する必要があります。%9\$d",$postid,$now,$socials['all'],$socials['twitter'],$socials['facebook'],$socials['google'],$socials['hatena'],$socials['pocket'],$socials['feedly']));}これは取得したSNSのカウントを、日時とともにデータベースへ書き込むというSQL文です。プレースホルダは%d、%s、%fで指定します。%dは整数型、%sは文字列、%fは少数をそれぞれ指定します。PHPのsprintfにおける型指定子(置換指示詞)と同じですね。対応する値はプレースホルダの数だけ、カンマ区切りで先頭から順番に指定していきます。'%2\$s'という指定もしています。「%s」という型指定子の間に「2\$」という位置指定子を挟んでます。これはプレースホルダに対応する値の2番目のもの(上の例で言う$now)を使うという指定です。ちなみにこの方法で位置を指定した場合、文字列は「‘(シングルクォート)」で囲む必要があります。require...」なるエラーが出ます。(個人的にはWordPress側のミスな気がしますが、注意してください)同じ値を繰り返し使うような場合は、このように指定します。以上のようにプレースホルダを使えば、カンマをエスケープしたり、SQL文をサニタイズしたりという手間が省けます。「渡す前に数列にするから安全だ」といった思い込みが一番危険なので、面倒でも入力値は全てプレースホルダを利用しましょう。それでもSQLインジェクションが発生したとしたら...、もうそれはWordPressの実装が悪いということです。諦めましょうw$wpdb->prepareのエラーメッセージ$wpdb->prepareで第2引数を使わないと以下の警告が出ます。in...第2引数移行を使わないということは、プレースホルダを使っていないということです。セキュリティに配慮した親切な警告ですね。間違っても第2引数に「''」を指定してエラーだけを回避するという対策はしないでください。他にも行の追加は$wpdb->insert()だったり、更新ならupdate()、削除ならdelete()という専用の関数も用意されてます。$tableにはテーブル名、$dataには配列でカラム名=>データ、$formatはオプションでプレースホルダに指定した型指定子を指定します。);これはWordPress内部でプレースホルダを利用しているので、SQLインジェクション対策は必要ありません。単純に特定のテーブルにデータを渡すだけという場合はこちらを利用しましょう。データベースへ保存したデータを取得する方法これは特に難しいことはありません。気をつけるとしたら、無駄に「*(アスタリスク)」で必要のないデータを取得しないことです。必要なカラムのデータだけを取得しましょう。);}取得するデータのクエリをget_row()に渡してます。複数の列がある場合はget_col()。複数行に渡る場合はget_results()を使います。オリジナルのクエリを組み立てるなら、保存の時と同じようにquery()を使います。オプション名など、ユーザーの入力値を使ってクエリを組み立てる場合は、保存時と同じように$wpdb->prepare()でプレースホルダを利用してください。データベースから取得したデータのエスケープまた、忘れてはならないのがエスケープ処理です。データベースから値を取得して出力する場合は全てエスケープ処理します。エスケープ処理が必要か例えばプラグインオリジナルの設定画面を作成してフォームに以下のデータを入力されたとします。<script>alert('hoge');</script><p>ふが</p>これがバリデーションや、プリペアドステートメントをすり抜けた場合、JavaScriptが実行されてしまいます。これは後述するオプションページの実装時でも同じです。「アドミン権限で入力するフォームにXSSが仕込まれるわけ無い」と思われるかもしれませんが「どこをエスケープして、どこをしないか」などと考えて記述すれば、必ず漏れがおきます。そのため、データベースから取得した値は、問答無用でエスケープ処理をしてください。手を抜くと以下のようにJavaScriptが実行されてしまいます。これがエスケープしておけば以下の様にフォームにタグが表示されます。良いエスケープのタイミングはHTMLに出力する直前です。テンプレートタグ等の場合はデータを渡す直前、もしくは変数に渡すタイミングです。エスケープの方法はセオリー通りで構いませんが、WordPressでは専用の関数を用意してくれているので、利用しましょう。主なエスケープは以下の通りです。esc_html<>&”’をエンティティ化esc_attr<>&”’をエンティティ化して、HTMLタグを取り除くesc_urlURL文字列として最適化する上の例で言えば以下のようにしておきましょう。);esc_htmlとesc_attrの違いCodexや解説サイトを見てもesc_htmlと、esc_attrの違いが理解できません。ネット上の解説を見ると、フォーム等のvalueなんかにはesc_attrを使おうという解説が多いようです。意味もわからずセキュリティ対策を勧めるのも何なので、違いを調べてみました。どちらもincludeディレクトリのformatting.phpで定義されています。);}全く同じですね...。いうことで、データベースの値を取得して出力する前にはesc_html()を使っておけば問題ないようです。関数を見れば分かる通り、配列を直接渡すことはできないので注意してください。次は「WordPressプラグイン用の設定を追加する方法」です。コメントをキャンセルコメントは認証制のため、すぐには反映されません。sukegra」をご利用ください。Share)Linuxの基本の基本。Share)他に運営しているサイトGOいけん世間を騒がせている、あの話題について言いたい。そんなあなたの「ご意見」を世に問うサイト。SUKEGRA「スケグラ」は日本語でプログラミングの悩みを解決するQ&Aサイトです。アクアリウムWikiアクアリウムに関することをみんなでまとめるWikiです。