Google Chrome のXSS仕様にはまる。

 

このページは、WordPressのプラグインを作成している方や、テーマ内のfunctions.phpより独自の設定管理を設けている方には参考になるのではないかと思っています。

もしかしたら私だけの影響かもしれませんが。

(その際はコメントフォームに何か一言言ってもらえると嬉しいです 🙂 )

もし試してみたいという方は、下記よりお試し下さい。
(ブラウザの影響と私は仮定しています。なのでブラウザが更新されて仕様が変わった場合は、別の動作になるのかもしれません。この現象はこの記事を書いている 2013年8月ごろの、とても暑い日が続く日の事です 😳 )

 

いきさつ

かなりの時間。はまりました。

とあるバグを報告してくれた方から、「あなたのプラグインでこの部分が設定できないよ。他は動くんだけどねとご報告がありました。

他は動く…?

ということは、動かない部分の記述や分岐が間違っていたりフックするタイミングや処理が間違っていたりするだろうな。と想定していました。

なので、そのような考えのもとで原因を探していました。

でもどれだけ試しても、バグの報告をしてくれた方と同じような状況にならず、想定通りの動作をしました。

う~ん、どうしたもんだろう。。とそういえば、以前動画ファイルでバグの症状を報告してくれた方がいました。

その方の動画を参考に、どのようなプラグインをインストールしているのかを調べ、できる限り同じような環境を作りました。

それで初めて、バグの症状が分かりました。

一言で言えば他プラグインの影響。と言ってしまえばそれまでですが。

しかし、有名なJetpackプラグインを使用している時、または WooCommerce Admin Bar Addition を使用している時のバグでした。
(どちらもプラグイン側のバグではありません)
 

で、色々と調べてみると

どうも、<form>タグ関係の場合だけ、バグが出るという症状でした。

どんどん調べていくと、結論としては、Google ChromeのXSS対策の仕様?と判断しました。 😳
正確にはプラグインの影響ではなく、そのプラグインの影響を可能にした場合の<form>タグ関連の影響でした。
(WordPressを一切使わず、シンプルなHTMLだけの場合でも試してみました)

これはプラグインうんぬんではなく、様々な場合に影響があると思っています。
「投稿」「固定ページ」等も含まれます。でも公開はできますが)

この症状を試してみたい方は以下をお試しください。

 

はじめに用意

試す方法として、まず用意するものが独自の設定画面。

できる限り他の影響を受けないようにする為にシンプルな設定にします。
テーマもプラグインも、WordPressをインストールしたばかりのデフォルトの状態が理想的です。

今回は簡単な設定ページを用意します。

まず設定ページを作成する為に、以下のコードをfunctions.phpなり、追記してください。

function ex_xss_menu() {
  add_menu_page( 'Example Xss' , 'Example Xss' , 'administrator' , 'ex_xss' , 'ex_xss_page' );
}
add_action( 'admin_menu' , 'ex_xss_menu' );

そして管理画面を読み込むと、設定の下のほうに「Example Xss」というメニューが追加されていると思います。(今はそのメニューをクリックしてもエラーが表示されます。まだメニューしか作成していないので。)

 

メニュー設置
メニュー設置

 

次にExample Xssの設定ページ作成用のコードです。先ほどのコードのところに追記してください。

function ex_xss_page() {
  if( !empty( $_POST["ex_text"] ) ) {
    update_option( "ex_text" , stripslashes( $_POST["ex_text"] ) );
  }
  if( !empty( $_POST["ex_area"] ) ) {
    update_option( "ex_area" , stripslashes( $_POST["ex_area"] ) );
  }

  echo '<div class="wrap">';
  echo '<h2>Example XSS Test</h2>';
  echo '<form action="" method="post">';

  echo sprintf( '<p>Input: <input name="ex_text" value="%s" style="width: 300px;" /></p>' , get_option( 'ex_text' ) );
  echo sprintf( '<p>Textarea: <textarea name="ex_area" rows="5" cols="10" style="width: 300px;">%s</textarea></p>' , get_option( 'ex_area' ) );
  echo sprintf( '<p class="submit"><input type="submit" value="%s" class="button button-primary" /></p>' , __( 'Submit' ) );

  echo '</form>';
  echo '</div>';
}

 

これでメニューをクリックすると、シンプルな設定ページが出来上がります。

設定ページ
設定ページ

 

あ、ここは重要です。

Google Chromeのコンソールを表示させておいてください。(キーボードのF12を押す)

コンソール表示
コンソール表示

コンソールで既にエラーが無いことを確認してください。エラーがある場合はそれなりに対処して、エラーが無い状態にしたほうがテストとしては理想的だと思います。

 

で、ここから。

バグとなってしまう症状を確認していきます。

作成した設定ページにinput text 、textareaの2つのフォームフィールドがあります。
どちらでもかまいませんが、何か、フォームを作成するように<form>タグを入力してください。サンプルとして私は以下のように入力しました。

フォーム入力例
フォーム入力例

で、送信ボタンを押して下さい。すると…なんと。

ちゃんとデータは保存されています。変な期待をした方ごめんなさい。 😳

でも、これは一回目の送信ボタンを押した時(一回目のデータ保存時)の動作です。

 

送信ボタンを押した直後、他のページに移動せずGoogle Chromeのコンソールを確認してみてください。

コンソール画面
コンソール画面

 

先ほどは何もエラーは表示されていませんでしたが、送信ボタンを押した直後にエラーが表示されます。しかし、入力したデータはきちんと保存されています

The XSS Auditor refused to execute a script in 'http://example.com/wp-admin/admin.php?page=ex_xss' because its source code was found within the request. The auditor was enabled as the server sent neither an 'X-XSS-Protection' nor 'Content-Security-Policy' header.

なにやらXSSに関してのエラー?注意?が出ていることが分かると思います。

 

ここが大事です。この状態でもう一度「送信」を押してみて下さい。

 

出ましたか?真っ白な何もない画面。アドレスバーにはabout:blank。 😯

Google Chrome だけ、このような仕様だとは全く予想していませんでした。

 

具体的には

あのコンソールの文章をもとに色々なブログを見て回って、私の個人的な考えですが、辺なコードを埋め込まれないようにする為の、Google ChromeのXSS対策処理ではないかと思います。

あ、Firefoxですか?バンバン保存できます。 :mrgreen:
それが良いのか悪いのかは別ですが。

ただ、もっと具体的にどのようなコードを記述すると、このような仕様になるのかを私なりに調べた結果、ひとつは分かりました。(多分、ひとつではなく複数あると思っています)

ちなみにその記述は、

action="

(アクション イコール ダブルクォーテーション)

調べた結果、フォームタグかどうかは関係が無いようでした。

action=”というような記述が問題の現象を引き起こしているようでした。

試してみたい方は、この記述をどこでもいいので記述してみてください。
「新規投稿」や「固定ページ」でも。あのコンソール文が表示されます。
(テキスト編集の場合です)

ただ、ちょっと面白いというか、これは良いのか? 😕 と思ったのですが、

action=''

このように記述すると、何のエラーも出ません。(全角ではありません)

違いは ダブルクォーテーションシングルクォーテーション か。それだけです。

なんでこんな仕様なんでしょうか。ちょっと分かりません。この記述は安全とみなされるのでしょうか。。ちょっとこの仕様に関しては理解が難しいです。  😕

ただ、やっとバグが出るタイミングがはっきりと分かりました。

この仕様が原因でプラグインの設定データが上手く保存出来ない。
という事に気づくまでに、ものすごく時間を取られました。 😳

 

うん、どう対処しようか。。

ダブルクォーテーションを正規表現の置換で強制にシングルクォーテーションに書き換えようか。または「Google chrome、今のところ上手く動きません」と表示させようか。(これは最終案…)

 

解決方法として

私なりに色々と調べた結果、X-XSS-Protection というヘッダーの値を 0 として出力するという事でした。
おそらく、「お願いだからXSSのフィルターチェックしないでね!」というサーバからの意思表示的な意味合いだと私は考えています。

先ほどのエラー文にはこう書いています。

The auditor was enabled as the server sent neither an 'X-XSS-Protection' nor 'Content-Security-Policy' header.

翻訳内容はおそらく、

サーバ管理者(auditor)は’X-XSS-Protection’ または ‘Content-Security-Policy’ヘッダーのどちらかをサーバから送信することができます。

このような意味だと解釈しました。どちらのヘッダーでも良さそうだったので、とりあえず今回は X-XSS-Protection ヘッダーを送信することにしました。両方送信したらどうなるんだろう?

 

じゃあこれをどのタイミングで出力すればいいんだろうと思って色々情報探してみました。

https://gist.github.com/ocean90/3622298

あ、wp_headers なるフックがあるんですね。今回はこの作者のコードをパクって参考に試してみます。 😉

function ex_xss_add_header( $headers, $object ) {
  $headers['X-XSS-Protection'] = 0;
  return $headers;
}
add_filter( 'wp_headers', 'ex_xss_add_header', 10, 2 );

これで無事、action=”を入力しても動作するようになりました。

 

※このコードを使おうと考えた方へ

このままの状態では注意が必要です。

このままだと、アクセスしたページ全てのヘッダーで’X-XSS-Protection’が出力されるので、事前に何かしら条件分岐の処理(管理画面のこの設定画面のこのデータが送信された時等)をしたほうが安全の為に良いと思います。

 

 

コメントを残す